Instrument Neutral Distributed Interface INDI  2.0.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 {
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 
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 
315 {
316  joystickCallbackFunc = JoystickCallback;
317 }
318 
320 {
321  axisCallbackFunc = AxisCallback;
322 }
323 
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 {
353  ControllerType targetType = CONTROLLER_UNKNOWN;
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 }
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
void setButtonCallback(buttonFunc buttonCallback)
setButtonCallback Sets the callback function when a new button input is detected.
static void joystickEvent(const char *joystick_n, double mag, double angle, void *context)
virtual bool ISSnoopDevice(XMLEle *root)
const char * getControllerSetting(const char *name)
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
void clearMap()
clearMap clears all properties added previously by mapController()
void mapController(const char *propertyName, const char *propertyLabel, ControllerType type, const char *initialValue)
mapController adds a new property to the joystick's settings.
virtual bool initProperties()
void setAxisCallback(axisFunc axisCallback)
setAxisCallback Sets the callback function when a new axis input is detected.
INDI::DefaultDevice * device
virtual bool saveConfigItems(FILE *fp)
virtual void ISGetProperties(const char *dev)
std::function< void(const char *button_n, ISState state, void *context)> buttonFunc
buttonFunc Button callback function signature.
axisFunc axisCallbackFunc
virtual bool updateProperties()
void setJoystickCallback(joystickFunc joystickCallback)
setJoystickCallback Sets the callback function when a new joystick input is detected.
joystickFunc joystickCallbackFunc
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
static void buttonEvent(const char *button_n, int value, void *context)
std::function< void(const char *axis_n, double value, void *context)> axisFunc
axisFunc Axis callback function signature.
Controller(INDI::DefaultDevice *cdevice)
Controller Default ctor.
ControllerType getControllerType(const char *name)
std::function< void(const char *joystick_n, double mag, double angle, void *context)> joystickFunc
joystickFunc Joystick callback function signature.
buttonFunc buttonCallbackFunc
static void axisEvent(const char *axis_n, int value, void *context)
Class to provide extended functionality for devices in addition to the functionality provided by INDI...
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_1OFMANY
Definition: indiapi.h:173
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indidevapi.c:25
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: indidevapi.c:291
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: indidevapi.c:158
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: indidevapi.c:198
void IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
Add a text vector property value to the configuration file.
Definition: indidevapi.c:20
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: indidevapi.c:235
IText * IUFindText(const ITextVectorProperty *tvp, const char *name)
Find an IText member in a vector text property.
Definition: indidevapi.c:56
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
Definition: indidriver.c:1396
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:143
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
#define DEBUGFDEVICE(device, priority, msg,...)
Definition: indilogger.h:61
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
Definition: lilxml.cpp:644
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition: lilxml.cpp:606
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition: lilxml.cpp:555
Namespace to encapsulate INDI client, drivers, and mediator classes.
__le16 type
Definition: pwc-ioctl.h:0
One text descriptor.
char name[MAXINDINAME]
Definition: indiapi.h:371
char name[MAXINDINAME]
Definition: indiapi.h:250