Instrument Neutral Distributed Interface INDI  2.0.2
joystickdriver.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2012 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 "joystickdriver.h"
24 
25 #include <cstring>
26 
27 #define MAX_JOYSTICKS 3
28 
30 {
31  active = false;
32  pollMS = 100;
33  joystick_fd = 0;
34  joystick_ev = new js_event();
35  joystick_st = new joystick_state();
36 
37  strncpy(dev_path, JOYSTICK_DEV, 256);
38 
42 }
43 
45 {
46  Disconnect();
47  delete joystick_st;
48  delete joystick_ev;
49 }
50 
52 {
53  joystickCallbackFunc = JoystickCallback;
54 }
55 
57 {
58  axisCallbackFunc = AxisCallback;
59 }
60 
62 {
63  buttonCallbackFunc = buttonCallback;
64 }
65 
66 void JoyStickDriver::setPort(const char *port)
67 {
68  strncpy(dev_path, port, 256);
69 }
70 
72 {
73  joystick_fd = open(dev_path, O_RDONLY | O_NONBLOCK);
74 
75  if (joystick_fd > 0)
76  {
77  ioctl(joystick_fd, JSIOCGNAME(256), name);
78  ioctl(joystick_fd, JSIOCGVERSION, &version);
79  ioctl(joystick_fd, JSIOCGAXES, &axes);
80  ioctl(joystick_fd, JSIOCGBUTTONS, &buttons);
81 
82  joystick_st->axis.reserve(axes);
83  joystick_st->button.reserve(buttons);
84  active = true;
85  pthread_create(&thread, 0, &JoyStickDriver::loop, this);
86  return true;
87  }
88 
89  return false;
90 }
91 
93 {
94  if (joystick_fd > 0)
95  {
96  active = false;
97  pthread_join(thread, 0);
98  close(joystick_fd);
99  }
100 
101  joystick_fd = 0;
102 
103  return true;
104 }
105 
106 void *JoyStickDriver::loop(void *obj)
107 {
108  while (reinterpret_cast<JoyStickDriver *>(obj)->active)
109  reinterpret_cast<JoyStickDriver *>(obj)->readEv();
110  return obj;
111 }
112 
114 {
115  int bytes = read(joystick_fd, joystick_ev, sizeof(*joystick_ev));
116  if (bytes > 0)
117  {
118  joystick_ev->type &= ~JS_EVENT_INIT;
119  if (joystick_ev->type & JS_EVENT_BUTTON)
120  {
121  joystick_st->button[joystick_ev->number] = joystick_ev->value;
122  buttonCallbackFunc(joystick_ev->number, joystick_ev->value);
123  }
124  if (joystick_ev->type & JS_EVENT_AXIS)
125  {
126  joystick_st->axis[joystick_ev->number] = joystick_ev->value;
127  int joystick_n = joystick_ev->number;
128  if (joystick_n % 2 != 0)
129  joystick_n--;
130  if (joystick_n / 2.0 < MAX_JOYSTICKS)
131  {
132  joystick_position pos = joystickPosition(joystick_n);
133 
134  // Reject noise
135  if (pos.r < 0.001)
136  {
137  pos.r = 0;
138  pos.theta = 0;
139  }
140 
141  joystickCallbackFunc(joystick_n / 2, pos.r, pos.theta);
142  }
143 
144  axisCallbackFunc(joystick_ev->number, joystick_ev->value);
145  }
146  }
147  else
148  usleep(pollMS * 1000);
149 }
150 
152 {
153  joystick_position pos;
154 
155  if (n > -1 && n < axes)
156  {
157  int i0 = n, i1 = n + 1;
158  float x0 = joystick_st->axis[i0] / 32767.0f, y0 = -joystick_st->axis[i1] / 32767.0f;
159  float x = x0 * sqrt(1 - pow(y0, 2) / 2.0f), y = y0 * sqrt(1 - pow(x0, 2) / 2.0f);
160 
161  pos.x = x0;
162  pos.y = y0;
163 
164  pos.theta = atan2(y, x) * (180.0 / 3.141592653589);
165  pos.r = sqrt(pow(y, 2) + pow(x, 2));
166 
167  // For direction keys and scale/throttle keys
168  if (pos.r == 0)
169  {
170  pos.r = -joystick_st->axis[i1];
171 
172  if (pos.r < 0)
173  {
174  // Left
175  if ((i0 % 2 == 0))
176  pos.theta = 180;
177  // Down
178  else
179  pos.theta = 270;
180  }
181  else
182  {
183  // Up
184  if ((i0 % 2 == 0))
185  pos.theta = 90;
186  // Right
187  else
188  pos.theta = 0;
189  }
190  }
191  else if (pos.theta < 0)
192  pos.theta += 360;
193 
194  // Make sure to reset angle if magnitude is zero
195  if (pos.r <= 0.001)
196  pos.theta = 0;
197  }
198  else
199  {
200  pos.theta = pos.r = pos.x = pos.y = 0.0f;
201  }
202 
203  return pos;
204 }
205 
207 {
208  return n > -1 && n < buttons ? joystick_st->button[n] : 0;
209 }
210 
212 {
213  pollMS = ms;
214 }
215 
216 void JoyStickDriver::joystickEvent(int joystick_n, double mag, double angle)
217 {
218  (void)joystick_n;
219  (void)mag;
220  (void)angle;
221 }
222 
223 void JoyStickDriver::axisEvent(int axis_n, int value)
224 {
225  (void)axis_n;
226  (void)value;
227 }
228 
229 void JoyStickDriver::buttonEvent(int button_n, int button_value)
230 {
231  (void)button_n;
232  (void)button_value;
233 }
234 
236 {
237  return name;
238 }
239 
241 {
242  return version;
243 }
244 
246 {
247  int n_joysticks = axes / 2;
248 
249  if (axes % 2 != 0)
250  n_joysticks++;
251 
252  if (n_joysticks > MAX_JOYSTICKS)
253  n_joysticks = MAX_JOYSTICKS;
254 
255  return n_joysticks;
256 }
257 
259 {
260  return axes;
261 }
262 
264 {
265  return buttons;
266 }
The JoyStickDriver class provides basic functionality to read events from supported game pads under L...
buttonFunc buttonCallbackFunc
static void buttonEvent(int button_n, int value)
static void * loop(void *obj)
static void axisEvent(int axis_n, int value)
void setButtonCallback(buttonFunc buttonCallback)
axisFunc axisCallbackFunc
joystickFunc joystickCallbackFunc
std::function< void(int axis_n, double value)> axisFunc
std::function< void(int joystick_n, double mag, double angle)> joystickFunc
void setAxisCallback(axisFunc axisCallback)
const char * getName()
static void joystickEvent(int joystick_n, double mag, double angle)
void setPoll(int ms)
void setJoystickCallback(joystickFunc joystickCallback)
bool buttonPressed(int n)
void setPort(const char *port)
std::function< void(int button_n, int value)> buttonFunc
joystick_position joystickPosition(int n)
#define MAX_JOYSTICKS
#define JOYSTICK_DEV
std::vector< signed short > axis
std::vector< signed short > button