Instrument Neutral Distributed Interface INDI  2.0.2
joystick.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2013 Jasem Mutlaq. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify it
5  under the terms of the GNU General Public License as published by the Free
6  Software Foundation; either version 2 of the License, or (at your option)
7  any later version.
8 
9  This program is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 
19  The full GNU General Public License is included in this distribution in the
20  file called LICENSE.
21 *******************************************************************************/
22 
23 #include "joystick.h"
24 
25 #include "joystickdriver.h"
26 #include "indistandardproperty.h"
27 
28 #include <memory>
29 #include <cstring>
30 
31 // We declare an auto pointer to joystick.
32 std::unique_ptr<JoyStick> joystick(new JoyStick());
33 
35 {
36  driver.reset(new JoyStickDriver());
37 }
38 
40 {
41  return "Joystick";
42 }
43 
45 {
46  bool rc = driver->Connect();
47 
48  if (rc)
49  {
50  LOG_INFO("Joystick is online.");
51 
52  setupParams();
53  }
54  else
55  LOG_INFO("Error: cannot find Joystick device.");
56 
57  return rc;
58 }
59 
61 {
62  LOG_INFO("Joystick is offline.");
63 
64  return driver->Disconnect();
65 }
66 
68 {
69  char propName[16] = {0}, propLabel[16] = {0};
70 
71  if (driver == nullptr)
72  return;
73 
74  int nAxis = driver->getNumOfAxes();
75  int nJoysticks = driver->getNumOfJoysticks();
76  int nButtons = driver->getNumrOfButtons();
77 
78  JoyStickNP = new INumberVectorProperty[nJoysticks];
79  JoyStickN = new INumber[nJoysticks * 2];
80 
81  AxisN = new INumber[nAxis];
82  DeadZoneN = new INumber[nAxis];
83 
84  ButtonS = new ISwitch[nButtons];
85 
86  for (int i = 0; i < nJoysticks * 2; i += 2)
87  {
88  snprintf(propName, 16, "JOYSTICK_%d", i / 2 + 1);
89  snprintf(propLabel, 16, "Joystick %d", i / 2 + 1);
90 
91  IUFillNumber(&JoyStickN[i], "JOYSTICK_MAGNITUDE", "Magnitude", "%g", -32767.0, 32767.0, 0, 0);
92  IUFillNumber(&JoyStickN[i + 1], "JOYSTICK_ANGLE", "Angle", "%g", 0, 360.0, 0, 0);
93  IUFillNumberVector(&JoyStickNP[i / 2], JoyStickN + i, 2, getDeviceName(), propName, propLabel, "Monitor", IP_RO,
94  0, IPS_IDLE);
95  }
96 
97  for (int i = 0; i < nAxis; i++)
98  {
99  snprintf(propName, 16, "AXIS_%d", i + 1);
100  snprintf(propLabel, 16, "Axis %d", i + 1);
101 
102  IUFillNumber(&AxisN[i], propName, propLabel, "%.f", -32767.0, 32767.0, 0, 0);
103  IUFillNumber(&DeadZoneN[i], propName, propLabel, "%.f", 0, 5000, 500, 5);
104  }
105 
106  IUFillNumberVector(&AxisNP, AxisN, nAxis, getDeviceName(), "JOYSTICK_AXES", "Axes", "Monitor", IP_RO, 0, IPS_IDLE);
107 
108  IUFillNumberVector(&DeadZoneNP, DeadZoneN, nAxis, getDeviceName(), "JOYSTICK_DEAD_ZONE", "Axes", "Dead Zones", IP_RW, 0,
109  IPS_IDLE);
110 
111  for (int i = 0; i < nButtons; i++)
112  {
113  snprintf(propName, 16, "BUTTON_%d", i + 1);
114  snprintf(propLabel, 16, "Button %d", i + 1);
115 
116  IUFillSwitch(&ButtonS[i], propName, propLabel, ISS_OFF);
117  }
118 
119  IUFillSwitchVector(&ButtonSP, ButtonS, nButtons, getDeviceName(), "JOYSTICK_BUTTONS", "Buttons", "Monitor", IP_RO,
120  ISR_NOFMANY, 0, IPS_IDLE);
121 }
122 
124 {
126 
127  IUFillText(&PortT[0], "PORT", "Port", "/dev/input/js0");
129 
130  IUFillText(&JoystickInfoT[0], "JOYSTICK_NAME", "Name", "");
131  IUFillText(&JoystickInfoT[1], "JOYSTICK_VERSION", "Version", "");
132  IUFillText(&JoystickInfoT[2], "JOYSTICK_NJOYSTICKS", "# Joysticks", "");
133  IUFillText(&JoystickInfoT[3], "JOYSTICK_NAXES", "# Axes", "");
134  IUFillText(&JoystickInfoT[4], "JOYSTICK_NBUTTONS", "# Buttons", "");
135  IUFillTextVector(&JoystickInfoTP, JoystickInfoT, 5, getDeviceName(), "JOYSTICK_INFO", "Joystick Info",
137 
138  addDebugControl();
139 
140  return true;
141 }
142 
144 {
146 
147  if (isConnected())
148  {
149  char buf[8];
150  // Name
151  IUSaveText(&JoystickInfoT[0], driver->getName());
152  // Version
153  snprintf(buf, 8, "%d", driver->getVersion());
154  IUSaveText(&JoystickInfoT[1], buf);
155  // # of Joysticks
156  snprintf(buf, 8, "%d", driver->getNumOfJoysticks());
157  IUSaveText(&JoystickInfoT[2], buf);
158  // # of Axes
159  snprintf(buf, 8, "%d", driver->getNumOfAxes());
160  IUSaveText(&JoystickInfoT[3], buf);
161  // # of buttons
162  snprintf(buf, 8, "%d", driver->getNumrOfButtons());
163  IUSaveText(&JoystickInfoT[4], buf);
164 
166 
167  for (int i = 0; i < driver->getNumOfJoysticks(); i++)
169 
172 
173  // Dead zones
175 
176  // N.B. Only set callbacks AFTER we define our properties above
177  // because these calls backs otherwise can be called asynchronously
178  // and they mess up INDI XML output
179  driver->setJoystickCallback(joystickHelper);
180  driver->setAxisCallback(axisHelper);
181  driver->setButtonCallback(buttonHelper);
182  }
183  else
184  {
186 
187  for (int i = 0; i < driver->getNumOfJoysticks(); i++)
188  deleteProperty(JoyStickNP[i].name);
189 
193 
194  delete[] JoyStickNP;
195  delete[] JoyStickN;
196  delete[] AxisN;
197  delete[] DeadZoneN;
198  delete[] ButtonS;
199  }
200 
201  return true;
202 }
203 
204 void JoyStick::ISGetProperties(const char *dev)
205 {
207 
210 
211  /*
212  if (isConnected())
213  {
214  for (int i = 0; i < driver->getNumOfJoysticks(); i++)
215  defineProperty(&JoyStickNP[i]);
216 
217  defineProperty(&AxisNP);
218  defineProperty(&ButtonSP);
219  }
220  */
221 }
222 
224 {
226 }
227 
228 bool JoyStick::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
229 {
230  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
231  {
232  if (strcmp(name, PortTP.name) == 0)
233  {
234  PortTP.s = IPS_OK;
235  IUUpdateText(&PortTP, texts, names, n);
236  // Update client display
237  IDSetText(&PortTP, nullptr);
238 
239  driver->setPort(PortT[0].text);
240 
241  return true;
242  }
243  }
244 
245  return DefaultDevice::ISNewText(dev, name, texts, names, n);
246 }
247 
248 bool JoyStick::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
249 {
250  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
251  {
252  if (!strcmp(name, DeadZoneNP.name))
253  {
254  IUUpdateNumber(&DeadZoneNP, values, names, n);
255  DeadZoneNP.s = IPS_OK;
256  IDSetNumber(&DeadZoneNP, nullptr);
257  return true;
258  }
259  }
260 
261  return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
262 }
263 
264 void JoyStick::joystickHelper(int joystick_n, double mag, double angle)
265 {
266  joystick->joystickEvent(joystick_n, mag, angle);
267 }
268 
269 void JoyStick::buttonHelper(int button_n, int value)
270 {
271  joystick->buttonEvent(button_n, value);
272 }
273 
274 void JoyStick::axisHelper(int axis_n, int value)
275 {
276  joystick->axisEvent(axis_n, value);
277 }
278 
279 void JoyStick::joystickEvent(int joystick_n, double mag, double angle)
280 {
281  if (!isConnected())
282  return;
283 
284  LOGF_DEBUG("joystickEvent[%d]: %g @ %g", joystick_n, mag, angle);
285 
286  if (mag == 0)
287  JoyStickNP[joystick_n].s = IPS_IDLE;
288  else
289  JoyStickNP[joystick_n].s = IPS_BUSY;
290 
291  JoyStickNP[joystick_n].np[0].value = mag;
292  JoyStickNP[joystick_n].np[1].value = angle;
293 
294  IDSetNumber(&JoyStickNP[joystick_n], nullptr);
295 }
296 
297 void JoyStick::axisEvent(int axis_n, int value)
298 {
299  if (!isConnected())
300  return;
301 
302  LOGF_DEBUG("axisEvent[%d]: %d", axis_n, value);
303 
304  // All values within deadzone is reset to zero.
305  if (std::abs(value) <= DeadZoneN[axis_n].value)
306  value = 0;
307 
308  if (value == 0)
309  AxisNP.s = IPS_IDLE;
310  else
311  AxisNP.s = IPS_BUSY;
312 
313  AxisNP.np[axis_n].value = value;
314 
315  IDSetNumber(&AxisNP, nullptr);
316 }
317 
318 void JoyStick::buttonEvent(int button_n, int value)
319 {
320  if (!isConnected())
321  return;
322 
323  LOGF_DEBUG("buttonEvent[%d]: %s", button_n, value > 0 ? "On" : "Off");
324 
325  ButtonSP.s = IPS_OK;
326  ButtonS[button_n].s = (value == 0) ? ISS_OFF : ISS_ON;
327 
328  IDSetSwitch(&ButtonSP, nullptr);
329 }
330 
332 {
334 
335  IUSaveConfigText(fp, &PortTP);
337 
338  return true;
339 }
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual void ISGetProperties(const char *dev)
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual bool ISSnoopDevice(XMLEle *root)
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
void addDebugControl()
Add Debug control to the driver.
The JoyStickDriver class provides basic functionality to read events from supported game pads under L...
The JoyStick class provides an INDI driver that displays event data from game pads....
Definition: joystick.h:36
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: joystick.cpp:123
JoyStick()
Definition: joystick.cpp:34
ISwitchVectorProperty ButtonSP
Definition: joystick.h:74
IText PortT[1]
Definition: joystick.h:78
static void buttonHelper(int button_n, int value)
Definition: joystick.cpp:269
virtual bool Disconnect() override
Disconnect from device.
Definition: joystick.cpp:60
IText JoystickInfoT[5]
Definition: joystick.h:81
INumberVectorProperty AxisNP
Definition: joystick.h:68
std::unique_ptr< JoyStickDriver > driver
Definition: joystick.h:83
static void joystickHelper(int joystick_n, double mag, double angle)
Definition: joystick.cpp:264
bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
Definition: joystick.cpp:331
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: joystick.cpp:248
virtual const char * getDefaultName() override
Definition: joystick.cpp:39
ITextVectorProperty PortTP
Definition: joystick.h:77
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
Definition: joystick.cpp:204
static void axisHelper(int axis_n, int value)
Definition: joystick.cpp:274
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: joystick.cpp:143
virtual bool ISSnoopDevice(XMLEle *root) override
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
Definition: joystick.cpp:223
void joystickEvent(int joystick_n, double mag, double angle)
Definition: joystick.cpp:279
INumberVectorProperty DeadZoneNP
Definition: joystick.h:71
ISwitch * ButtonS
Definition: joystick.h:75
INumber * AxisN
Definition: joystick.h:69
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
Definition: joystick.cpp:228
virtual bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
Definition: joystick.cpp:44
INumberVectorProperty * JoyStickNP
Definition: joystick.h:65
void axisEvent(int axis_n, int value)
Definition: joystick.cpp:297
void setupParams()
Definition: joystick.cpp:67
INumber * JoyStickN
Definition: joystick.h:66
ITextVectorProperty JoystickInfoTP
Definition: joystick.h:80
void buttonEvent(int button_n, int value)
Definition: joystick.cpp:318
INumber * DeadZoneN
Definition: joystick.h:72
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
void ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Update the value of an existing text vector property.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ IP_RO
Definition: indiapi.h:184
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_NOFMANY
Definition: indiapi.h:175
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidevapi.c:272
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 IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indidevapi.c:36
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indidevapi.c:15
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 IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
Definition: indidevapi.c:180
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
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
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
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:1362
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOG_INFO(txt)
Definition: indilogger.h:74
std::unique_ptr< JoyStick > joystick(new JoyStick())
const char * DEVICE_PORT
Device serial (or bluetooth) connection port. The default value on Linux is /dev/ttyUSB0 while on Mac...
One number descriptor.
One switch descriptor.
Number vector property descriptor.
Definition: indiapi.h:319
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371
char name[MAXINDINAME]
Definition: indiapi.h:250