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 {
Controller(DefaultDevice * cdevice)25 Controller::Controller(DefaultDevice *cdevice)
26 {
27 device = cdevice;
28
29 JoystickSettingT = nullptr;
30 JoystickSettingTP.ntp = 0;
31
32 joystickCallbackFunc = joystickEvent;
33 axisCallbackFunc = axisEvent;
34 buttonCallbackFunc = buttonEvent;
35 }
36
~Controller()37 Controller::~Controller()
38 {
39 for (int i = 0; i < JoystickSettingTP.ntp; i++)
40 free(JoystickSettingT[i].aux0);
41
42 free(JoystickSettingT);
43 }
44
mapController(const char * propertyName,const char * propertyLabel,ControllerType type,const char * initialValue)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
clearMap()80 void Controller::clearMap()
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
initProperties()93 bool Controller::initProperties()
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,
98 IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
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
ISGetProperties(const char * dev)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
updateProperties()122 bool Controller::updateProperties()
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
ISNewSwitch(const char * dev,const char * name,ISState * states,char * names[],int n)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
ISNewText(const char * dev,const char * name,char * texts[],char * names[],int n)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
ISSnoopDevice(XMLEle * root)223 bool Controller::ISSnoopDevice(XMLEle *root)
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
saveConfigItems(FILE * fp)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
enableJoystick()295 void Controller::enableJoystick()
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
disableJoystick()309 void Controller::disableJoystick()
310 {
311 device->deleteProperty(JoystickSettingTP.name);
312 }
313
setJoystickCallback(joystickFunc JoystickCallback)314 void Controller::setJoystickCallback(joystickFunc JoystickCallback)
315 {
316 joystickCallbackFunc = JoystickCallback;
317 }
318
setAxisCallback(axisFunc AxisCallback)319 void Controller::setAxisCallback(axisFunc AxisCallback)
320 {
321 axisCallbackFunc = AxisCallback;
322 }
323
setButtonCallback(buttonFunc buttonCallback)324 void Controller::setButtonCallback(buttonFunc buttonCallback)
325 {
326 buttonCallbackFunc = buttonCallback;
327 }
328
joystickEvent(const char * joystick_n,double mag,double angle,void * context)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
axisEvent(const char * axis_n,int value,void * context)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
buttonEvent(const char * button_n,int button_value,void * context)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
getControllerType(const char * name)351 Controller::ControllerType Controller::getControllerType(const char *name)
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
getControllerSetting(const char * name)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 }
374