YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
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
14using namespace yarp::dev;
15using namespace yarp::sig;
16using namespace yarp::os;
17using namespace SDLJoypadImpl;
18
19namespace {
20YARP_LOG_COMPONENT(SDLJOYPAD, "yarp.device.SDLJoypad")
22}
23
24
25
27
29
30bool SDLJoypad::open(yarp::os::Searchable& rf)
31{
32 if(rf.check("help"))
33 {
34 yCInfo(SDLJOYPAD) << "parameters:";
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. ";
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
54 {
55 yCError(SDLJOYPAD, "Unable to initialize Joystick: %s", SDL_GetError());
56 return false;
57 }
58
59 joy_id = 0;
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 }
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 {
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
161bool 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;
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
254{
255 axes_count = m_axisCount;
256 return true;
257}
258
260{
261 button_count = m_buttonCount;
262 return true;
263}
264
266{
267 trackball_count = m_ballCount;
268 return true;
269}
270
272{
273 hat_count = m_hatCount;
274 return true;
275}
276
278{
279 touch_count = m_touchCount;
280 return true;
281}
282
284{
285 stick_count = m_stickCount;
286 return true;
287}
288
289bool 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
300bool 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 {
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 {
321 m_actionTimestamp = yarp::os::Time::now();
322 }
323 return true;
324}
325
326bool 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 {
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
349bool 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
357yarp::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
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
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
392{
393 return false;
394}
395
396bool 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 {
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
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 {
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
448void SDLJoypad::updateJoypad()
449{
451}
bool ret
yarp::sig::Vector Vector3(const double &x, const double &y)
SDLJoypad: Device that reads inputs of Joypads compatible with the SDL library.
Definition SDLJoypad.h:52
bool getRawAxisCount(unsigned int &axis_count) override
bool getRawButtonCount(unsigned int &button_count) override
bool getRawTouchSurfaceCount(unsigned int &touch_count) override
bool getRawStickDoF(unsigned int stick_id, unsigned int &DoF) override
bool getRawHat(unsigned int hat_id, unsigned char &value) override
bool getRawTrackballCount(unsigned int &trackball_count) override
bool close() override
Close the DeviceDriver.
bool getRawButton(unsigned int button_id, float &value) override
bool getRawAxis(unsigned int axis_id, double &value) override
bool getRawStickCount(unsigned int &stick_count) override
bool getRawHatCount(unsigned int &hat_count) override
bool getRawStick(unsigned int stick_id, yarp::sig::Vector &value, JoypadCtrl_coordinateMode coordinate_mode) override
bool getRawTrackball(unsigned int trackball_id, yarp::sig::Vector &value) override
bool getRawTouch(unsigned int touch_id, yarp::sig::Vector &value) override
std::map< int, std::string > m_actions
virtual bool executeAction(int action_id)
A simple collection of objects that can be described and transmitted in a portable way.
Definition Bottle.h:64
A mini-server for performing network communication in the background.
A base class for nested structures that can be searched.
Definition Searchable.h:31
void resize(size_t size) override
Resize the vector.
Definition Vector.h:221
void push_back(const T &elem)
Push a new element in the vector: size is changed.
Definition Vector.h:268
#define yCInfo(component,...)
#define yCError(component,...)
#define yCWarning(component,...)
#define YARP_LOG_COMPONENT(name,...)
For streams capable of holding different kinds of content, check what they actually have.
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.
The main, catch-all namespace for YARP.
Definition dirs.h:16