Instrument Neutral Distributed Interface INDI  1.9.2
indicontroller.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright (C) 2013 Jasem Mutlaq <mutlaqja@ikarustech.com>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License version 2 as published by the Free Software Foundation.
7 
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  Library General Public License for more details.
12 
13  You should have received a copy of the GNU Library General Public License
14  along with this library; see the file COPYING.LIB. If not, write to
15  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  Boston, MA 02110-1301, USA.
17 *******************************************************************************/
18 
19 #include "indicontroller.h"
20 
21 #include <cstring>
22 
23 namespace INDI
24 {
25 Controller::Controller(DefaultDevice *cdevice)
26 {
27  device = cdevice;
28 
29  JoystickSettingT = nullptr;
30  JoystickSettingTP.ntp = 0;
31 
35 }
36 
38 {
39  for (int i = 0; i < JoystickSettingTP.ntp; i++)
40  free(JoystickSettingT[i].aux0);
41 
42  free(JoystickSettingT);
43 }
44 
45 void Controller::mapController(const char *propertyName, const char *propertyLabel, ControllerType type,
46  const char *initialValue)
47 {
48  if (JoystickSettingT == nullptr)
49  JoystickSettingT = static_cast<IText *>(malloc(sizeof(IText)));
50 
51  // Ignore duplicates
52  for (int i = 0; i < JoystickSettingTP.ntp; i++)
53  {
54  if (!strcmp(propertyName, JoystickSettingT[i].name))
55  return;
56  }
57 
58  IText *buf = static_cast<IText *>(realloc(JoystickSettingT, (JoystickSettingTP.ntp + 1) * sizeof(IText)));
59  if (buf == nullptr)
60  {
61  free (JoystickSettingT);
62  perror("Failed to allocate memory for joystick controls.");
63  return;
64  }
65  else
66  JoystickSettingT = buf;
67 
68  ControllerType *ctype = static_cast<ControllerType *>(malloc(sizeof(ControllerType)));
69  *ctype = type;
70 
71  memset(JoystickSettingT + JoystickSettingTP.ntp, 0, sizeof(IText));
72  IUFillText(&JoystickSettingT[JoystickSettingTP.ntp], propertyName, propertyLabel, initialValue);
73 
74  JoystickSettingT[JoystickSettingTP.ntp++].aux0 = ctype;
75 
76  IUFillTextVector(&JoystickSettingTP, JoystickSettingT, JoystickSettingTP.ntp, device->getDeviceName(),
77  "JOYSTICKSETTINGS", "Settings", "Joystick", IP_RW, 0, IPS_IDLE);
78 }
79 
81 {
82  for (int i = 0; i < JoystickSettingTP.ntp; i++)
83  {
84  free(JoystickSettingT[i].aux0);
85  free(JoystickSettingT[i].text);
86  }
87 
88  JoystickSettingTP.ntp = 0;
89  free(JoystickSettingT);
90  JoystickSettingT = nullptr;
91 }
92 
94 {
95  IUFillSwitch(&UseJoystickS[0], "ENABLE", "Enable", ISS_OFF);
96  IUFillSwitch(&UseJoystickS[1], "DISABLE", "Disable", ISS_ON);
97  IUFillSwitchVector(&UseJoystickSP, UseJoystickS, 2, device->getDeviceName(), "USEJOYSTICK", "Joystick", OPTIONS_TAB,
99 
100  IUFillText(&JoystickDeviceT[0], "SNOOP_JOYSTICK_DEVICE", "Device", "Joystick");
101  IUFillTextVector(&JoystickDeviceTP, JoystickDeviceT, 1, device->getDeviceName(), "SNOOP_JOYSTICK", "Snoop Joystick",
102  OPTIONS_TAB, IP_RW, 60, IPS_IDLE);
103 
104  return true;
105 }
106 
107 void Controller::ISGetProperties(const char *dev)
108 {
109  if (dev != nullptr && strcmp(dev, device->getDeviceName()))
110  return;
111 
112  if (device->isConnected())
113  {
114  device->defineProperty(&UseJoystickSP);
115  device->defineProperty(&JoystickDeviceTP);
116 
117  if (JoystickSettingT && UseJoystickS[0].s == ISS_ON)
118  device->defineProperty(&JoystickSettingTP);
119  }
120 }
121 
123 {
124  if (device->isConnected())
125  {
126  device->defineProperty(&UseJoystickSP);
127  device->defineProperty(&JoystickDeviceTP);
128 
129  if (JoystickSettingT && UseJoystickS[0].s == ISS_ON)
130  device->defineProperty(&JoystickSettingTP);
131  }
132  else
133  {
134  device->deleteProperty(UseJoystickSP.name);
135  device->deleteProperty(JoystickDeviceTP.name);
136  device->deleteProperty(JoystickSettingTP.name);
137  }
138 
139  return true;
140 }
141 
142 bool Controller::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
143 {
144  if (strcmp(dev, device->getDeviceName()) == 0)
145  {
146  // Enable joystick support
147  if (!strcmp(name, UseJoystickSP.name))
148  {
149  IUUpdateSwitch(&UseJoystickSP, states, names, n);
150 
151  UseJoystickSP.s = IPS_OK;
152 
153  if (UseJoystickSP.sp[0].s == ISS_ON)
154  enableJoystick();
155  else
156  disableJoystick();
157 
158  IDSetSwitch(&UseJoystickSP, nullptr);
159 
160  return true;
161  }
162  }
163 
164  return false;
165 }
166 
167 bool Controller::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
168 {
169  if (strcmp(dev, device->getDeviceName()) == 0)
170  {
171  if (!strcmp(name, "SNOOP_JOYSTICK"))
172  {
173  IUUpdateText(&JoystickDeviceTP, texts, names, n);
174  JoystickDeviceTP.s = IPS_IDLE;
175 
176  IDSetText(&JoystickDeviceTP, nullptr);
177 
178  if (UseJoystickSP.sp[0].s == ISS_ON)
179  {
180  // Let's switch over to the new joystick.
181  enableJoystick();
182  }
183 
184  return true;
185  }
186 
187  if (!strcmp(name, "JOYSTICKSETTINGS") && n <= JoystickSettingTP.ntp)
188  {
189  for (int i = 0; i < JoystickSettingTP.ntp; i++)
190  {
191  IText *tp = IUFindText(&JoystickSettingTP, names[i]);
192  if (tp)
193  {
194  ControllerType cType = getControllerType(texts[i]);
195  ControllerType myType = *(static_cast<ControllerType *>(JoystickSettingT[i].aux0));
196  if (cType != myType)
197  {
198  JoystickSettingTP.s = IPS_ALERT;
199  IDSetText(&JoystickSettingTP, nullptr);
200  DEBUGFDEVICE(dev, INDI::Logger::DBG_ERROR, "Cannot change controller type to %s.", texts[i]);
201  return false;
202  }
203  }
204  }
205 
206  IUUpdateText(&JoystickSettingTP, texts, names, n);
207 
208  for (int i = 0; i < n; i++)
209  {
210  if (strstr(JoystickSettingT[i].text, "JOYSTICK_"))
211  IDSnoopDevice(JoystickDeviceT[0].text, JoystickSettingT[i].text);
212  }
213 
214  JoystickSettingTP.s = IPS_OK;
215  IDSetText(&JoystickSettingTP, nullptr);
216  return true;
217  }
218  }
219 
220  return false;
221 }
222 
224 {
225  XMLEle *ep = nullptr;
226  double mag = 0, angle = 0;
227 
228  // If joystick is disabled, do not process anything.
229  if (UseJoystickSP.sp[0].s == ISS_OFF)
230  return false;
231 
232  const char *propName = findXMLAttValu(root, "name");
233 
234  // Check axis
235  if (!strcmp("JOYSTICK_AXES", propName))
236  {
237  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
238  {
239  const char *elemName = findXMLAttValu(ep, "name");
240  const char *setting = getControllerSetting(elemName);
241  if (setting == nullptr)
242  continue;
243 
244  mag = atof(pcdataXMLEle(ep));
245 
246  axisCallbackFunc(setting, mag, device);
247  }
248  }
249  // Check buttons
250  else if (!strcmp("JOYSTICK_BUTTONS", propName))
251  {
252  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
253  {
254  const char *elemName = findXMLAttValu(ep, "name");
255  const char *setting = getControllerSetting(elemName);
256 
257  if (setting == nullptr)
258  continue;
259 
260  buttonCallbackFunc(setting, strcmp(pcdataXMLEle(ep), "Off") ? ISS_ON : ISS_OFF, device);
261  }
262  }
263  // Check joysticks
264  else if (strstr(propName, "JOYSTICK_"))
265  {
266  const char *setting = getControllerSetting(propName);
267 
268  // We don't have this here, so let's not process it
269  if (setting == nullptr)
270  return false;
271 
272  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
273  {
274  if (!strcmp("JOYSTICK_MAGNITUDE", findXMLAttValu(ep, "name")))
275  mag = atof(pcdataXMLEle(ep));
276  else if (!strcmp("JOYSTICK_ANGLE", findXMLAttValu(ep, "name")))
277  angle = atof(pcdataXMLEle(ep));
278  }
279 
280  joystickCallbackFunc(setting, mag, angle, device);
281  }
282 
283  return false;
284 }
285 
286 bool Controller::saveConfigItems(FILE *fp)
287 {
288  IUSaveConfigSwitch(fp, &UseJoystickSP);
289  IUSaveConfigText(fp, &JoystickSettingTP);
290  IUSaveConfigText(fp, &JoystickDeviceTP);
291 
292  return true;
293 }
294 
296 {
297  device->defineProperty(&JoystickSettingTP);
298 
299  for (int i = 0; i < JoystickSettingTP.ntp; i++)
300  {
301  if (strstr(JoystickSettingTP.tp[i].text, "JOYSTICK_"))
302  IDSnoopDevice(JoystickDeviceT[0].text, JoystickSettingTP.tp[i].text);
303  }
304 
305  IDSnoopDevice(JoystickDeviceT[0].text, "JOYSTICK_AXES");
306  IDSnoopDevice(JoystickDeviceT[0].text, "JOYSTICK_BUTTONS");
307 }
308 
310 {
311  device->deleteProperty(JoystickSettingTP.name);
312 }
313 
314 void Controller::setJoystickCallback(joystickFunc JoystickCallback)
315 {
316  joystickCallbackFunc = JoystickCallback;
317 }
318 
319 void Controller::setAxisCallback(axisFunc AxisCallback)
320 {
321  axisCallbackFunc = AxisCallback;
322 }
323 
324 void Controller::setButtonCallback(buttonFunc buttonCallback)
325 {
326  buttonCallbackFunc = buttonCallback;
327 }
328 
329 void Controller::joystickEvent(const char *joystick_n, double mag, double angle, void *context)
330 {
331  INDI_UNUSED(joystick_n);
332  INDI_UNUSED(mag);
333  INDI_UNUSED(angle);
334  INDI_UNUSED(context);
335 }
336 
337 void Controller::axisEvent(const char *axis_n, int value, void *context)
338 {
339  INDI_UNUSED(axis_n);
340  INDI_UNUSED(value);
341  INDI_UNUSED(context);
342 }
343 
344 void Controller::buttonEvent(const char *button_n, int button_value, void *context)
345 {
346  INDI_UNUSED(button_n);
347  INDI_UNUSED(button_value);
348  INDI_UNUSED(context);
349 }
350 
352 {
354 
355  if (strstr(name, "JOYSTICK_"))
356  targetType = CONTROLLER_JOYSTICK;
357  else if (strstr(name, "AXIS_"))
358  targetType = CONTROLLER_AXIS;
359  else if (strstr(name, "BUTTON_"))
360  targetType = CONTROLLER_BUTTON;
361 
362  return targetType;
363 }
364 
365 const char *Controller::getControllerSetting(const char *name)
366 {
367  for (int i = 0; i < JoystickSettingTP.ntp; i++)
368  if (!strcmp(JoystickSettingT[i].text, name))
369  return JoystickSettingT[i].name;
370 
371  return nullptr;
372 }
373 }
INDI::Controller::getControllerType
ControllerType getControllerType(const char *name)
Definition: indicontroller.cpp:367
INDI::Controller::~Controller
virtual ~Controller()
Definition: indicontroller.cpp:53
INDI::Controller::CONTROLLER_UNKNOWN
@ CONTROLLER_UNKNOWN
Definition: indicontroller.h:84
INDI::Controller::buttonEvent
static void buttonEvent(const char *button_n, int value, void *context)
Definition: indicontroller.cpp:360
IPS_OK
@ IPS_OK
Definition: indiapi.h:161
INDI::Controller::device
INDI::DefaultDevice * device
Definition: indicontroller.h:164
INDI::Controller::saveConfigItems
virtual bool saveConfigItems(FILE *fp)
Definition: indicontroller.cpp:302
ISS_OFF
@ ISS_OFF
Definition: indiapi.h:150
pcdataXMLEle
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition: lilxml.c:575
IDSetText
void IDSetText(const ITextVectorProperty *t, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing text vector property.
IPS_ALERT
@ IPS_ALERT
Definition: indiapi.h:163
nextXMLEle
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition: lilxml.c:524
IDSnoopDevice
void IDSnoopDevice(const char *snooped_device, const char *snooped_property)
Function a Driver calls to snoop on another Device. Snooped messages will then arrive via ISSnoopDevi...
Definition: indidriver.c:137
INDI::DefaultDevice::defineProperty
void defineProperty(INumberVectorProperty *property)
Definition: defaultdevice.cpp:997
INDI::Controller::axisEvent
static void axisEvent(const char *axis_n, int value, void *context)
Definition: indicontroller.cpp:353
OPTIONS_TAB
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
Definition: defaultdevice.cpp:39
INDI::Controller::setButtonCallback
void setButtonCallback(buttonFunc buttonCallback)
setButtonCallback Sets the callback function when a new button input is detected.
Definition: indicontroller.cpp:340
INDI::Logger::DBG_ERROR
@ DBG_ERROR
Definition: indilogger.h:192
IUFillTextVector
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidriver.c:477
INDI::Controller::Controller
Controller(INDI::DefaultDevice *cdevice)
Controller Default ctor.
Definition: indicontroller.cpp:41
INDI_UNUSED
#define INDI_UNUSED(x)
Definition: indidevapi.h:799
_ITextVectorProperty::ntp
int ntp
Definition: indiapi.h:263
INDI::BaseDevice::getDeviceName
const char * getDeviceName() const
Definition: basedevice.cpp:799
IUFillText
void IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL.
Definition: indidriver.c:369
IUUpdateText
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
Definition: indidriver.c:259
INDI::Controller::mapController
void mapController(const char *propertyName, const char *propertyLabel, ControllerType type, const char *initialValue)
mapController adds a new property to the joystick's settings.
Definition: indicontroller.cpp:61
IUFindText
IText * IUFindText(const ITextVectorProperty *tvp, const char *name)
Find an IText member in a vector text property.
Definition: indicom.c:1341
INDI::Controller::CONTROLLER_AXIS
@ CONTROLLER_AXIS
Definition: indicontroller.h:84
type
__le16 type
Definition: pwc-ioctl.h:2
INDI::Controller::clearMap
void clearMap()
clearMap clears all properties added previously by mapController()
Definition: indicontroller.cpp:96
_ITextVectorProperty::tp
IText * tp
Definition: indiapi.h:261
INDI::Controller::disableJoystick
void disableJoystick()
Definition: indicontroller.cpp:325
INDI::Controller::setAxisCallback
void setAxisCallback(axisFunc axisCallback)
setAxisCallback Sets the callback function when a new axis input is detected.
Definition: indicontroller.cpp:335
IUSaveConfigText
void IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
Add a text vector property value to the configuration file.
Definition: indicom.c:1439
IText
One text descriptor.
INDI::Controller::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Definition: indicontroller.cpp:158
INDI::Controller::ISSnoopDevice
virtual bool ISSnoopDevice(XMLEle *root)
Definition: indicontroller.cpp:239
INDI::Controller::ISGetProperties
virtual void ISGetProperties(const char *dev)
Definition: indicontroller.cpp:123
IUFillSwitchVector
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidriver.c:412
INDI::Controller::CONTROLLER_JOYSTICK
@ CONTROLLER_JOYSTICK
Definition: indicontroller.h:84
ISR_1OFMANY
@ ISR_1OFMANY
Definition: indiapi.h:172
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
xml_ele_
Definition: lilxml.c:105
INDI::Controller::getControllerSetting
const char * getControllerSetting(const char *name)
Definition: indicontroller.cpp:381
IUUpdateSwitch
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:171
INDI::Controller::ControllerType
ControllerType
Definition: indicontroller.h:84
_ITextVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:249
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
INDI::Controller::setJoystickCallback
void setJoystickCallback(joystickFunc joystickCallback)
setJoystickCallback Sets the callback function when a new joystick input is detected.
Definition: indicontroller.cpp:330
indicontroller.h
INDI::Controller::joystickCallbackFunc
joystickFunc joystickCallbackFunc
Definition: indicontroller.h:160
INDI::Controller::CONTROLLER_BUTTON
@ CONTROLLER_BUTTON
Definition: indicontroller.h:84
INDI::Controller::joystickEvent
static void joystickEvent(const char *joystick_n, double mag, double angle, void *context)
Definition: indicontroller.cpp:345
_ISwitchVectorProperty::s
IPState s
Definition: indiapi.h:382
DEBUGFDEVICE
#define DEBUGFDEVICE(device, priority, msg,...)
Definition: indilogger.h:61
_ITextVectorProperty::s
IPState s
Definition: indiapi.h:259
INDI
Namespace to encapsulate INDI client, drivers, and mediator classes.
Definition: AlignmentSubsystemForClients.cpp:11
INDI::Controller::buttonCallbackFunc
buttonFunc buttonCallbackFunc
Definition: indicontroller.h:161
findXMLAttValu
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
Definition: lilxml.c:613
IP_RW
@ IP_RW
Definition: indiapi.h:185
INDI::Controller::initProperties
virtual bool initProperties()
Definition: indicontroller.cpp:109
ISState
ISState
Switch state.
Definition: indiapi.h:148
_ISwitchVectorProperty::sp
ISwitch * sp
Definition: indiapi.h:384
INDI::Controller::enableJoystick
void enableJoystick()
Definition: indicontroller.cpp:311
IUSaveConfigSwitch
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indicom.c:1444
INDI::DefaultDevice::deleteProperty
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
Definition: defaultdevice.cpp:965
IDSetSwitch
void void void void void IDSetSwitch(const ISwitchVectorProperty *s, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing switch vector property.
INDI::Controller::ISNewText
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Definition: indicontroller.cpp:183
IUFillSwitch
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
Definition: indidriver.c:320
INDI::Controller::updateProperties
virtual bool updateProperties()
Definition: indicontroller.cpp:138
INDI::Controller::axisCallbackFunc
axisFunc axisCallbackFunc
Definition: indicontroller.h:162
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
ISS_ON
@ ISS_ON
Definition: indiapi.h:151