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