GamepadUnit.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package RobotAPI::ArmarXObjects::GamepadUnit
17 * @author Simon Ottenhaus ( simon dot ottenhaus at kit dot edu )
18 * @date 2017
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23#include "GamepadUnit.h"
24
28
29#include <linux/joystick.h>
30
31using namespace armarx;
32
33void
35{
37 offeringTopic(getProperty<std::string>("GamepadTopicName").getValue());
38 deviceName = getProperty<std::string>("GamepadDeviceName").getValue();
39 deviceEventName = getProperty<std::string>("GamepadForceFeedbackName").getValue();
40 readTask = new RunningTask<GamepadUnit>(this, &GamepadUnit::run, "GamepadUnit");
41}
42
43void
45{
47 topicPrx =
48 getTopic<GamepadUnitListenerPrx>(getProperty<std::string>("GamepadTopicName").getValue());
50 sendTask = new SimplePeriodicTask<>(
51 [&]
52 {
54 std::unique_lock lock(mutex);
55 if (!js.opened())
56 {
57 return;
58 }
60 if (!dataTimestamp)
61 {
62 ARMARX_INFO << deactivateSpam(1) << "dataTimestamp is null, waiting for value";
63 return;
64 }
65 ARMARX_CHECK_NOT_NULL(dataTimestamp);
66 const IceUtil::Time age = IceUtil::Time::now() - dataTimestamp->toTime();
67 if (age.toMilliSeconds() < getProperty<int>("PublishTimeout").getValue())
68 {
70 ARMARX_CHECK_NOT_NULL(topicPrx) << "Topic proxy must not be null.";
71 topicPrx->reportGamepadState(deviceName, js.name, data, dataTimestamp);
72 }
73 else
74 {
76 ARMARX_INFO << deactivateSpam(100000, std::to_string(dataTimestamp->getTimestamp()))
77 << "No new signal from gamepad for " << age.toMilliSecondsDouble()
78 << " milliseconds. Not sending data. Timeout: "
79 << getProperty<int>("PublishTimeout").getValue() << " ms";
80 }
81 },
82 30);
83
84 sendTask->start();
87}
88
89void
90GamepadUnit::vibrate(const ::Ice::Current&)
91{
92 ARMARX_INFO << "vibration!";
93 js.executeEffect();
94}
95
96bool
98{
99 if (js.open(deviceName, deviceEventName))
100 {
101
103 ARMARX_INFO << "opened a gamepad named " << js.name << " with " << js.numberOfAxis
104 << " axis and " << js.numberOfButtons << " buttons.";
105 if (js.numberOfAxis == 8 && js.numberOfButtons == 11)
106 {
108 readTask->start();
109 }
110 else
111 {
113 ARMARX_WARNING << "this is not our trusty logitech gamepad.";
114 js.close();
115 return false;
116 }
117 }
118 else
119 {
121 ARMARX_WARNING << "Could not open gamepad device " << deviceName;
122 js.close();
123 return false;
124 }
125 return true;
126}
127
128void
129GamepadUnit::run()
130{
132 while (readTask->isRunning())
133 {
135 if (!js.pollEvent())
136 {
138 ARMARX_WARNING << "failed to read gamepad data - trying to reconnect";
139 js.close();
140 sleep(1);
141 while (readTask->isRunning() && !openGamepadConnection())
142 {
143 sleep(1);
144 }
145 }
147 std::unique_lock lock(mutex);
148 IceUtil::Time now = IceUtil::Time::now();
149 dataTimestamp = new TimestampVariant(now);
150
151 //mapping found with command line tool jstest <device file>
152
153 float axisFactor = 1.0f / 32768.f;
154
155 data.leftStickY = js.axis[0] * axisFactor;
156 data.leftStickX = js.axis[1] * axisFactor;
157 data.rightStickX = js.axis[3] * axisFactor;
158 data.rightStickY = js.axis[4] * axisFactor;
159 data.dPadX = js.axis[7] * axisFactor;
160 data.dPadY = js.axis[6] * axisFactor;
161 data.leftTrigger = js.axis[2] * axisFactor;
162 data.rightTrigger = js.axis[5] * axisFactor;
164
165 data.leftButton = js.buttonsPressed[4];
166 data.rightButton = js.buttonsPressed[5];
167 data.backButton = js.buttonsPressed[6];
168 data.startButton = js.buttonsPressed[7];
169 data.xButton = js.buttonsPressed[2];
170 data.yButton = js.buttonsPressed[3];
171 data.aButton = js.buttonsPressed[0];
172 data.bButton = js.buttonsPressed[1];
173 data.theMiddleButton = js.buttonsPressed[8];
174 data.leftStickButton = js.buttonsPressed[9];
175 data.rightStickButton = js.buttonsPressed[10];
177
178 ARMARX_VERBOSE << "left x (integer): " << js.axis[0]
179 << " left x (float): " << data.leftStickX
180 << " right trigger: " << data.rightTrigger;
181
182 //usleep(1000); // 10ms
183 }
184}
185
186void
188{
190 if (sendTask)
191 {
193 sendTask->stop();
194 }
195 if (readTask)
196 {
198 readTask->stop();
199 }
200}
201
202void
206
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
Property< PropertyType > getProperty(const std::string &name)
void onInitComponent() override
void onDisconnectComponent() override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void onConnectComponent() override
void vibrate(const ::Ice::Current &=::Ice::emptyCurrent) override
void onExitComponent() override
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
Definition Logging.cpp:99
void offeringTopic(const std::string &name)
Registers a topic for retrival after initialization.
TopicProxyType getTopic(const std::string &name)
Returns a proxy of the specified topic.
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
SimplePeriodicTask(Ts...) -> SimplePeriodicTask< std::function< void(void)> >
#define ARMARX_TRACE
Definition trace.h:77