YARP
Yet Another Robot Platform
SDLJoypad.cpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3  * SPDX-License-Identifier: LGPL-2.1-or-later
4  */
5 
6 #include "SDLJoypad.h"
7 #include <cstdio>
8 #include <yarp/os/LogStream.h>
9 #include <cmath>
10 #include <yarp/os/Time.h>
11 #include <iostream>
12 
13 
14 using namespace yarp::dev;
15 using namespace yarp::sig;
16 using namespace yarp::os;
17 using namespace SDLJoypadImpl;
18 
19 namespace {
20 YARP_LOG_COMPONENT(SDLJOYPAD, "yarp.device.SDLJoypad")
21 constexpr double actionsExecutionTime = 1.0;
22 }
23 
24 
25 
26 SDLJoypad::SDLJoypad() = default;
27 
28 SDLJoypad::~SDLJoypad() = default;
29 
30 bool SDLJoypad::open(yarp::os::Searchable& rf)
31 {
32  if(rf.check("help"))
33  {
34  yCInfo(SDLJOYPAD) << "parameters:";
35  yCInfo(SDLJOYPAD);
36  yCInfo(SDLJOYPAD) << "UseAllJoypadAsOne - set it to 1 to have all the connected joypad as one";
37  yCInfo(SDLJOYPAD) << "DefaultJoystickNumber - select the id of the joypad to use if there are more than one joypad and UseAllJoypadAsOne is set to 0";
38  yCInfo(SDLJOYPAD) << "stick - the number of stick to configure. a stick is simply a wrapping of 2 or more axes so for every stick";
39  yCInfo(SDLJOYPAD) << " a group named STICK*ID* containing the stick's parameters is searched. ";
40  yCInfo(SDLJOYPAD);
41  yCInfo(SDLJOYPAD) << "stick groups parameters:";
42  yCInfo(SDLJOYPAD) << "axes - axes count for this stick";
43  yCInfo(SDLJOYPAD) << "axis[ID]_id - axis id for current stick related axis";
44  yCInfo(SDLJOYPAD) << "invert_axis_[ID] - invert the current axis";
45  yCInfo(SDLJOYPAD) << "deadZone - set the deadzone for this stick";
46  return false;
47  }
48 
49  int joy_id;
50  size_t joystick_num;
51  int actionCount;
52 
53  if (SDL_InitSubSystem( SDL_INIT_JOYSTICK ) < 0 )
54  {
55  yCError(SDLJOYPAD, "Unable to initialize Joystick: %s", SDL_GetError());
56  return false;
57  }
58 
59  joy_id = 0;
60  joystick_num = SDL_NumJoysticks();
61  actionCount = 0;
62 
63  if (joystick_num == 0)
64  {
65  yCError(SDLJOYPAD, "No joysticks found");
66  return false;
67  }
68  else if (joystick_num == 1)
69  {
70  joy_id = 0;
71  yCInfo(SDLJOYPAD, "One joystick found");
72  yCInfo(SDLJOYPAD, "Using joystick: %s", SDL_JoystickName(joy_id));
73  }
74  else
75  {
76  yCInfo(SDLJOYPAD, "More than one joystick found:");
77  for (size_t i = 0; i < joystick_num; i++)
78  {
79  yCInfo(SDLJOYPAD) << i << ":" << SDL_JoystickName(i);
80  }
81  yCInfo(SDLJOYPAD);
82  if(!rf.check("UseAllJoypadAsOne"))
83  {
84  if(rf.find("UseAllJoypadAsOne").asBool())
85  {
86  // choose between multiple joysticks
87  if (rf.check("DefaultJoystickNumber"))
88  {
89  joy_id = rf.find("DefaultJoystickNumber").asInt32();
90  yCInfo(SDLJOYPAD, "Multiple joysticks found, using #%d, as specified in the configuration options", joy_id);
91  }
92  else
93  {
94  yCWarning(SDLJOYPAD, "No default joystick specified in the configuration options");
95  yCWarning(SDLJOYPAD, "Which joystick you want to use? (choose number)");
96  std::cin >> joy_id;
97  }
98  m_allJoypad = false;
99  }
100  else
101  {
102  m_allJoypad = true;
103  }
104  }
105  else
106  {
107  yCError(SDLJOYPAD) << "Missing UseAllJoypadAsOne parameter";
108  return false;
109  }
110  }
111 
112  if(m_allJoypad)
113  {
114  for(size_t i = 0; i < joystick_num; ++i)
115  {
116  m_device.push_back(SDL_JoystickOpen(i));
117  }
118  }
119  else
120  {
121  m_device.push_back(SDL_JoystickOpen(joy_id));
122  }
123 
124  for(size_t i = 0; i < m_device.size(); ++i)
125  {
126  if ( m_device[i] == nullptr )
127  {
128  yCError(SDLJOYPAD) << "Could not open joystick with id" << i;
129  return false;
130  }
131 
132  // Obtaining Joystick capabilities
133  m_axisCount += SDL_JoystickNumAxes(m_device[i]);
134  m_ballCount += SDL_JoystickNumBalls(m_device[i]);
135  m_hatCount += SDL_JoystickNumHats(m_device[i]);
136  m_buttonCount += SDL_JoystickNumButtons(m_device[i]);
137  }
138 
139  if(parseActions(rf, &actionCount))
140  {
141  if(actionCount)
142  {
143  if(SDL_JoystickEventState(SDL_ENABLE) < 0)
144  {
145  yCError(SDLJOYPAD) << "SDLJoypad:" << SDL_GetError();
146  return false;
147  }
148  yCInfo(SDLJOYPAD) << "Actions successfully parsed and linked to the joypad";
149  }
150  }
151  else
152  {
153  yCError(SDLJOYPAD) << "Error while parsing actions";
154  return false;
155  }
156 
157  if(!parseStickInfo(rf)){return false;}
158  return true;
159 }
160 
161 bool SDLJoypad::parseStickInfo(const yarp::os::Searchable& cfg)
162 {
163  if(!cfg.check("sticks") || !cfg.find("sticks").isInt32())
164  {
165  yCError(SDLJOYPAD) << "Missing 'sticks' parameter or not an integer";
166  return false;
167  }
168 
169  for(unsigned int i = 0; i < m_axisCount; i++)
170  {
171  m_axes.push_back(true);
172  }
173 
174  m_stickCount = cfg.find("sticks").asInt32();
175  for(unsigned int i = 0; i < m_stickCount; i++)
176  {
177  std::string stickName;
178  int axesCount;
179  stick currentStick;
180 
181  stickName = "STICK"+std::to_string(i);
182 
183  if(!cfg.check(stickName))
184  {
185  yCError(SDLJOYPAD) << "Missing" << stickName << "group in configuration";
186  return false;
187  }
188 
189  Bottle& stickParams = cfg.findGroup(stickName);
190 
191  if(0 == stickParams.size())
192  {
193  yCError(SDLJOYPAD) << "Group" << stickName << "is empty";
194  return false;
195  }
196 
197  if(!stickParams.check("axes") || !stickParams.find("axes").isInt32())
198  {
199  yCError(SDLJOYPAD) << "Missing 'axes' count in" << stickName << "group or not an integer";
200  return false;
201  }
202 
203  axesCount = stickParams.find("axes").asInt32();
204 
205  for(int j = 0; j < axesCount; j++)
206  {
207  std::string axisName, invertName;
208  unsigned int axis_id;
209  axisName = "axis" + std::to_string(j) + "_id";
210  invertName = "invert_axis_" + std::to_string(j);
211 
212  if(!stickParams.check(axisName) || !stickParams.find(axisName).isInt32())
213  {
214  yCError(SDLJOYPAD) << "Missing" << axisName << "param in" << stickName << "group or not an integer.";
215  return false;
216  }
217 
218  axis_id = (unsigned int)stickParams.find(axisName).asInt32();
219  if(axis_id > m_axisCount - 1)
220  {
221  yCError(SDLJOYPAD) << "Axis id out of bound";
222  return false;
223  }
224 
225  if(!stickParams.check(invertName) || !stickParams.find(invertName).isBool())
226  {
227  yCError(SDLJOYPAD) << "Missing" << invertName << "param in" << stickName << "group or not an bool.";
228  return false;
229  }
230 
231  currentStick.axes_ids.push_back(axis_id);
232  currentStick.direction.push_back(stickParams.find(invertName).asBool() ? -1 : 1);
233  m_axes[axis_id] = false;
234  }
235 
236  if(!stickParams.check("deadZone") || !stickParams.find("deadZone").isFloat64())
237  {
238  yCError(SDLJOYPAD) << "Missing deadZone param in" << stickName << "group or not an double.";
239  return false;
240  }
241 
242  currentStick.deadZone = stickParams.find("deadZone").asFloat64();
243  m_sticks.push_back(currentStick);
244  }
245  return true;
246 }
247 
249 {
250  return false;
251 }
252 
253 bool SDLJoypad::getRawAxisCount(unsigned int& axes_count)
254 {
255  axes_count = m_axisCount;
256  return true;
257 }
258 
259 bool SDLJoypad::getRawButtonCount(unsigned int& button_count)
260 {
261  button_count = m_buttonCount;
262  return true;
263 }
264 
265 bool SDLJoypad::getRawTrackballCount(unsigned int& trackball_count)
266 {
267  trackball_count = m_ballCount;
268  return true;
269 }
270 
271 bool SDLJoypad::getRawHatCount(unsigned int& hat_count)
272 {
273  hat_count = m_hatCount;
274  return true;
275 }
276 
277 bool SDLJoypad::getRawTouchSurfaceCount(unsigned int& touch_count)
278 {
279  touch_count = m_touchCount;
280  return true;
281 }
282 
283 bool SDLJoypad::getRawStickCount(unsigned int& stick_count)
284 {
285  stick_count = m_stickCount;
286  return true;
287 }
288 
289 bool SDLJoypad::getRawStickDoF(unsigned int stick_id, unsigned int& DoF)
290 {
291  if(stick_id > m_sticks.size()-1)
292  {
293  yCError(SDLJOYPAD) << "SDL_Joypad: stick_id out of bounds when calling 'getStickDoF'' method";
294  return false;
295  }
296  DoF = 2;
297  return true;
298 }
299 
300 bool SDLJoypad::getRawButton(unsigned int button_id, float& value)
301 {
302  if(button_id > m_buttonCount - 1){yCError(SDLJOYPAD) << "Button id out of bound!"; return false;}
303  updateJoypad();
304  size_t i;
305  for(i = 0; i < m_device.size(); ++i)
306  {
307  unsigned int localCount = SDL_JoystickNumButtons(m_device[i]);
308  if(button_id > localCount - 1)
309  {
310  button_id -= localCount;
311  }
312  else
313  {
314  break;
315  }
316  }
317  value = float(SDL_JoystickGetButton(m_device[i], button_id));
318  if(value > 0.5 && m_actions.find(button_id) != m_actions.end() && yarp::os::Time::now() - m_actionTimestamp > actionsExecutionTime)
319  {
320  executeAction(button_id);
321  m_actionTimestamp = yarp::os::Time::now();
322  }
323  return true;
324 }
325 
326 bool SDLJoypad::getPureAxis(unsigned int axis_id, double& value)
327 {
328  if(axis_id > m_axisCount - 1){yCError(SDLJOYPAD) << "Axis id out of bound!"; return false;}
329  size_t i;
330 
331  for(i = 0; i < m_device.size(); ++i)
332  {
333  unsigned int localCount;
334  localCount = SDL_JoystickNumAxes(m_device[i]);
335  if(axis_id > localCount - 1)
336  {
337  axis_id -= localCount;
338  }
339  else
340  {
341  break;
342  }
343  }
344 
345  value = 2 * ((float(SDL_JoystickGetAxis(m_device[i], axis_id)) - (-32.768)) / 0xffff);
346  return true;
347 }
348 
349 bool SDLJoypad::getRawAxis(unsigned int axis_id, double& value)
350 {
351  if(axis_id > m_axisCount - 1){yCError(SDLJOYPAD) << "Axis id out of bound!"; return false;}
352  //if(!m_axes.at(axis_id)) {yCWarning(SDLJOYPAD) << "Requested axis is part of a stick!";}
353  updateJoypad();
354  return getPureAxis(axis_id, value);
355 }
356 
357 yarp::sig::Vector Vector3(const double& x, const double& y)
358 {
359  Vector ret;
360  ret.push_back(x);
361  ret.push_back(y);
362  return ret;
363 }
364 
365 bool SDLJoypad::getRawStick(unsigned int stick_id, yarp::sig::Vector& value, JoypadCtrl_coordinateMode coordinate_mode)
366 {
367  if (stick_id > m_stickCount - 1){yCError(SDLJOYPAD) << "Stick id out of bound!"; return false;}
368  value.clear();
369  updateJoypad();
370  stick& stk = m_sticks[stick_id];
371  double val;
372 
373  for(size_t i = 0; i < stk.axes_ids.size(); i++)
374  {
375  if(!getRawAxis(stk.axes_ids[i], val)) {return false;}
376  value.push_back(val * stk.direction[i] * (fabs(val) > stk.deadZone));
377  }
378 
379  if (coordinate_mode == JypCtrlcoord_POLAR)
380  {
381  if (stk.axes_ids.size() > 2)
382  {
383  yCError(SDLJOYPAD) << "Polar coordinate system is supported only for bidimensional stick at the moment";
384  return false;
385  }
386  value = Vector3(sqrt(value[0] * value[0] + value[1] * value[1]), atan2(value[0], value[1]));
387  }
388  return true;
389 }
390 
391 bool SDLJoypad::getRawTouch(unsigned int touch_id, yarp::sig::Vector& value)
392 {
393  return false;
394 }
395 
396 bool SDLJoypad::getRawHat(unsigned int hat_id, unsigned char& value)
397 {
398  if(hat_id > m_hatCount - 1){yCError(SDLJOYPAD) << "Axis id out of bound!"; return false;}
399  updateJoypad();
400  size_t i;
401  for(i = 0; i < m_device.size(); ++i)
402  {
403  unsigned int localCount = SDL_JoystickNumHats(m_device[i]);
404  if(hat_id > localCount - 1)
405  {
406  hat_id -= localCount;
407  }
408  else
409  {
410  break;
411  }
412  }
413 
414  value = SDL_JoystickGetHat(m_device[i], hat_id);//TODO: map from their HAT define to our in case of #define changes
415  return true;
416 }
417 
418 bool SDLJoypad::getRawTrackball(unsigned int trackball_id, yarp::sig::Vector& value)
419 {
420  if(trackball_id > m_ballCount - 1){yCError(SDLJOYPAD) << "Trackball id out of bound!"; return false;}
421  updateJoypad();
422  int x, y;
423  size_t i;
424  for(i = 0; i < m_device.size(); ++i)
425  {
426  unsigned int localCount = SDL_JoystickNumBalls(m_device[i]);
427  if(trackball_id > localCount - 1)
428  {
429  trackball_id -= localCount;
430  }
431  else
432  {
433  break;
434  }
435  }
436  if(SDL_JoystickGetBall(m_device[i], trackball_id, &x, &y) == -1)
437  {
438  yCError(SDLJOYPAD) << "SDL_JoystickGetBall returned error";
439  return false;
440  }
441 
442  value.resize(2);
443  value[0] = x;
444  value[1] = y;
445  return true;
446 }
447 
448 void SDLJoypad::updateJoypad()
449 {
450  SDL_JoystickUpdate();
451 }
bool ret
yarp::sig::Vector Vector3(const double &x, const double &y)
Definition: SDLJoypad.cpp:357
SDLJoypad: Device that reads inputs of Joypads compatible with the SDL library.
Definition: SDLJoypad.h:52
bool getRawAxisCount(unsigned int &axis_count) override
Definition: SDLJoypad.cpp:253
bool getRawButtonCount(unsigned int &button_count) override
Definition: SDLJoypad.cpp:259
bool getRawTouchSurfaceCount(unsigned int &touch_count) override
Definition: SDLJoypad.cpp:277
bool getRawStickDoF(unsigned int stick_id, unsigned int &DoF) override
Definition: SDLJoypad.cpp:289
bool getRawHat(unsigned int hat_id, unsigned char &value) override
Definition: SDLJoypad.cpp:396
bool getRawTrackballCount(unsigned int &trackball_count) override
Definition: SDLJoypad.cpp:265
bool close() override
Close the DeviceDriver.
Definition: SDLJoypad.cpp:248
bool getRawButton(unsigned int button_id, float &value) override
Definition: SDLJoypad.cpp:300
bool getRawAxis(unsigned int axis_id, double &value) override
Definition: SDLJoypad.cpp:349
bool getRawStickCount(unsigned int &stick_count) override
Definition: SDLJoypad.cpp:283
bool getRawHatCount(unsigned int &hat_count) override
Definition: SDLJoypad.cpp:271
bool getRawStick(unsigned int stick_id, yarp::sig::Vector &value, JoypadCtrl_coordinateMode coordinate_mode) override
Definition: SDLJoypad.cpp:365
bool getRawTrackball(unsigned int trackball_id, yarp::sig::Vector &value) override
Definition: SDLJoypad.cpp:418
bool getRawTouch(unsigned int touch_id, yarp::sig::Vector &value) override
Definition: SDLJoypad.cpp:391
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:74
size_type size() const
Gets the number of elements in the bottle.
Definition: Bottle.cpp:251
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Definition: Bottle.cpp:277
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition: Bottle.cpp:287
A base class for nested structures that can be searched.
Definition: Searchable.h:66
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
virtual Bottle & findGroup(const std::string &key) const =0
Gets a list corresponding to a given keyword.
virtual yarp::conf::float64_t asFloat64() const
Get 64-bit floating point value.
Definition: Value.cpp:222
virtual bool isBool() const
Checks if value is a boolean.
Definition: Value.cpp:114
virtual bool asBool() const
Get boolean value.
Definition: Value.cpp:186
virtual std::int32_t asInt32() const
Get 32-bit integer value.
Definition: Value.cpp:204
virtual bool isFloat64() const
Checks if value is a 64-bit floating point number.
Definition: Value.cpp:150
virtual bool isInt32() const
Checks if value is a 32-bit integer.
Definition: Value.cpp:132
void resize(size_t size) override
Resize the vector.
Definition: Vector.h:222
void push_back(const T &elem)
Push a new element in the vector: size is changed.
Definition: Vector.h:250
#define yCInfo(component,...)
Definition: LogComponent.h:132
#define yCError(component,...)
Definition: LogComponent.h:154
#define yCWarning(component,...)
Definition: LogComponent.h:143
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:77
std::string to_string(IntegerType x)
Definition: numeric.h:115
An interface for the device drivers.
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition: Time.cpp:121
An interface to the operating system, including Port based communication.
Signal processing.
Definition: Image.h:22
The main, catch-all namespace for YARP.
Definition: dirs.h:16
std::vector< unsigned int > axes_ids
Definition: SDLJoypad.h:23
std::vector< int > direction
Definition: SDLJoypad.h:25