vrpn 07.35
Virtual Reality Peripheral Network
 
Loading...
Searching...
No Matches
vrpn_CHProducts_Controller_Raw.C
Go to the documentation of this file.
1// vrpn_CHProducts_Controller_Raw.C: VRPN driver for CHProducts Controller Raw devices
2
3#include <stdio.h> // for fprintf, stderr, NULL
4#include <string.h> // for memset
5#include <math.h> // for sqrt and fabs
6
8
10
11#if defined(VRPN_USE_HID)
12
13// USB vendor and product IDs for the models we support
14static const vrpn_uint16 CHPRODUCTS_VENDOR = 0x068e;
15static const vrpn_uint16 FIGHTERSTICK_USB = 0x00f3;
16
17static const double POLL_INTERVAL = 1e+6 / 30.0; // If we have not heard, ask.
18
19#define GAMEPAD_TRIGGER_THRESHOLD 30
20
22// helpers
24
25static vrpn_float64 normalize_dpad(unsigned char up, unsigned char right, unsigned char down, unsigned char left)
26{
27 int x = 0;
28 int y = 0;
29 if (right) {
30 x += 1;
31 }
32 if (left) {
33 x -= 1;
34 }
35 if (up) {
36 y += 1;
37 }
38 if (down) {
39 y -= 1;
40 }
41 size_t index = ((x + 1) * 3) + (y + 1);
42 vrpn_float64 angles[] = {225, 270, 315, 180, -1, 0, 135, 90, 45};
43 return (angles[index]);
44}
45
46static void normalize_axis(const unsigned int value, const short deadzone, const vrpn_float64 scale, vrpn_float64& channel, int wordSize = 16)
47{
48 channel = (static_cast<float>(value) - (float) (1 << (wordSize - 1)));
49 if (fabs(channel) < (deadzone * 3 / 4))
50 {
51 channel = 0.0f;
52 }
53 else
54 {
55 channel /= (float) (1 << (wordSize - 1));
56 }
57 channel *= scale;
58 if (channel < -1.0) { channel = -1.0; }
59 if (channel > 1.0) { channel = 1.0; }
60}
61
62static void normalize_axes(const unsigned int x, const unsigned int y, const short deadzone, const vrpn_float64 scale, vrpn_float64& channelX, vrpn_float64& channelY, int wordSize = 16)
63{
64 normalize_axis(x, deadzone, scale, channelX, wordSize);
65 normalize_axis(y, deadzone, scale, channelY, wordSize);
66}
67
69// Common base class
72 vrpn_uint16 vendor, vrpn_uint16 product) :
73 vrpn_BaseClass(name, c)
75 , _filter(filter)
76{
77 init_hid();
78}
79
81{
82 try {
83 delete _filter;
84 } catch (...) {
85 fprintf(stderr, "vrpn_CHProducts_Controller_Raw::~vrpn_CHProducts_Controller_Raw(): delete failed\n");
86 return;
87 }
88}
89
91{
92 // Get notifications when clients connect and disconnect
95}
96
97void vrpn_CHProducts_Controller_Raw::on_data_received(size_t bytes, vrpn_uint8 *buffer)
98{
99 decodePacket(bytes, buffer);
100}
101
103{
104 return (0);
105}
106
108{
109 return (0);
110}
111
113// ST290 Pro Joystick
116vrpn_CHProducts_Controller_Raw(new vrpn_HidProductAcceptor(CHPRODUCTS_VENDOR, FIGHTERSTICK_USB), name, c, CHPRODUCTS_VENDOR, FIGHTERSTICK_USB),
117 vrpn_Analog(name, c), vrpn_Button_Filter(name, c), vrpn_Dial(name, c)
118{
122
123 // Initialize the state of all the analogs, buttons, and dials
124 memset(buttons, 0, sizeof(buttons));
125 memset(lastbuttons, 0, sizeof(lastbuttons));
126 memset(channel, 0, sizeof(channel));
127 memset(last, 0, sizeof(last));
128}
129
131{
132 update();
134 struct timeval current_time;
135 vrpn_gettimeofday(&current_time, NULL);
136 if (vrpn_TimevalDuration(current_time, _timestamp) > POLL_INTERVAL)
137 {
138 _timestamp = current_time;
140
141 // Call the server_mainloop on our unique base class.
143 }
144}
145
146void vrpn_CHProducts_Fighterstick_USB::report(vrpn_uint32 class_of_service)
147{
150 if (vrpn_Dial::num_dials > 0)
151 {
153 }
154
155 vrpn_Analog::report_changes(class_of_service);
157 if (vrpn_Dial::num_dials > 0)
158 {
160 }
161}
162
163void vrpn_CHProducts_Fighterstick_USB::report_changes(vrpn_uint32 class_of_service)
164{
167 if (vrpn_Dial::num_dials > 0)
168 {
170 }
171
172 vrpn_Analog::report(class_of_service);
174 if (vrpn_Dial::num_dials > 0)
175 {
177 }
178}
179
180void vrpn_CHProducts_Fighterstick_USB::decodePacket(size_t bytes, vrpn_uint8 *buffer)
181{
182 // Fighterstick USB joystick
183
184 // Decode all full reports, each of which is 6 bytes long.
185 // Because there is only one type of report, the initial "0" report-type
186 // byte is removed by the HIDAPI driver.
187 /*
188 [0]: X-axis (left=00, right=ff, center=80)
189 [1]: Y-axis (up=00, down=ff, center=80)
190 [2]: throttle wheel (up=00, down=ff)
191 [3]: buttons high nibble: 0x10=trigger, 0x20=top red, 0x40=upper index red (toggles buttons 17-19), 0x80=pinky red,
192 - - low nibble 8-way POV hat upper-right on top: none=0x00, N=0x01, NE=0x02, ... NW=0x08
193 [4]: high nibble 4-way hat #2 (lower-right on top): none=0x00, N=0x10, E=0x20, S=0x40, W=0x80
194 - - low nibble 4-way hat #1 (left on top): none=0x00, N=0x01, E=0x02, S=0x04, W=0x08
195 [5]: upper nibble mode bits: 0x10=green, 0x20=red, 0x40=yellow, 0x80=<not used>
196 - - low nibble 4-way hat #3 (thumb): none=0x00, N=0x01, E=0x02, S=0x04, W=0x08
197 */
198 // XXX Check to see that this works with HIDAPI, there may be two smaller reports.
199 if (bytes == 6)
200 {
201 normalize_axes(buffer[0], buffer[1], 0x08, 1.0f, channel[0], channel[1], 8);
202 normalize_axis(buffer[2], 0x08, 1.0f, channel[2], 8);
203
204 vrpn_uint8 value, mask;
205 value = (buffer[3] >> 4);
206 for (int btn = 0; btn < 4; btn++)
207 {
208 mask = static_cast<vrpn_uint8>(1 << (btn % 8));
209 buttons[btn] = ((value & mask) != 0);
210 }
211
212 // Point of View Hat
213 buttons[4] = buttons[5] = buttons[6] = buttons[7] = 0;
214 switch (buffer[3] & 0x0f)
215 {
216 case 1: // up
217 buttons[4] = true;
218 break;
219 case 2:
220 buttons[4] = buttons[5] = true;
221 break;
222 case 3: // right
223 buttons[5] = true;
224 break;
225 case 4:
226 buttons[5] = buttons[6] = true;
227 break;
228 case 5: // down
229 buttons[6] = true;
230 break;
231 case 6:
232 buttons[6] = buttons[7] = true;
233 break;
234 case 7: // left
235 buttons[7] = true;
236 break;
237 case 8:
238 buttons[7] = buttons[4] = true;
239 break;
240 case 0:
241 default:
242 // nothing to do
243 break;
244 }
245 channel[3] = normalize_dpad(buttons[4], buttons[5], buttons[6], buttons[7]);
246
247 // 4-way Hat #2
248 buttons[8] = buttons[9] = buttons[10] = buttons[11] = 0;
249 switch (buffer[4] >> 4)
250 {
251 case 1: // up
252 buttons[8] = true;
253 break;
254 case 2: // right
255 buttons[9] = true;
256 break;
257 case 4: // down
258 buttons[10] = true;
259 break;
260 case 8: // left
261 buttons[11] = true;
262 break;
263 case 0:
264 default:
265 // nothing to do
266 break;
267 }
268 channel[4] = normalize_dpad(buttons[8], buttons[9], buttons[10], buttons[11]);
269 // 4-way Hat #1
270 buttons[12] = buttons[13] = buttons[14] = buttons[15] = 0;
271 switch (buffer[4] & 0x0f)
272 {
273 case 1: // up
274 buttons[12] = true;
275 break;
276 case 2: // right
277 buttons[13] = true;
278 break;
279 case 4: // down
280 buttons[14] = true;
281 break;
282 case 8: // left
283 buttons[15] = true;
284 break;
285 case 0:
286 default:
287 // nothing to do
288 break;
289 }
290 channel[5] = normalize_dpad(buttons[12], buttons[13], buttons[14], buttons[15]);
291
292 // mode
293 // keep pseudo-button pressed to indicate mode
294 //buttons[16] = buttons[17] = buttons[18] = buttons[19] = 0;
295 switch (buffer[5] >> 4)
296 {
297 case 1: // green
298 buttons[16] = true;
299 buttons[17] = buttons[18] = false;
300 break;
301 case 2: // red
302 buttons[17] = true;
303 buttons[16] = buttons[18] = false;
304 break;
305 case 4: // yellow
306 buttons[18] = true;
307 buttons[16] = buttons[17] = false;
308 break;
309/*
310 case 8: // none
311 buttons[19] = true;
312 break;
313*/
314 case 0:
315 default:
316 // nothing to do
317 break;
318 }
319 if (buttons[16] || buttons[17] || buttons[18] || buttons[19])
320 {
321 channel[6] = (normalize_dpad(buttons[16], buttons[17], buttons[18], buttons[19]) / 90.0f) + 1.0f;
322 }
323 // 4-way Hat #3
324 buttons[20] = buttons[21] = buttons[22] = buttons[23] = 0;
325 switch (buffer[5] & 0x0f)
326 {
327 case 1: // up
328 buttons[20] = true;
329 break;
330 case 2: // right
331 buttons[21] = true;
332 break;
333 case 4: // down
334 buttons[22] = true;
335 break;
336 case 8: // left
337 buttons[23] = true;
338 break;
339 case 0:
340 default:
341 // nothing to do
342 break;
343 }
344 channel[7] = normalize_dpad(buttons[20], buttons[21], buttons[22], buttons[23]);
345 }
346 else
347 {
348 fprintf(stderr, "vrpn_CHProducts_Fighterstick_USB: Found a corrupted report; # total bytes = %u\n", static_cast<unsigned>(bytes));
349 }
350}
351
352// End of VRPN_USE_HID
353#endif
vrpn_float64 last[vrpn_CHANNEL_MAX]
Definition vrpn_Analog.h:39
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition vrpn_Analog.h:38
vrpn_Analog(const char *name, vrpn_Connection *c=NULL)
Definition vrpn_Analog.C:14
struct timeval timestamp
Definition vrpn_Analog.h:41
vrpn_int32 num_channel
Definition vrpn_Analog.h:40
virtual void report(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY, const struct timeval time=vrpn_ANALOG_NOW)
Send a report whether something has changed or not (for servers) Optionally, tell what time to stamp ...
Definition vrpn_Analog.C:94
virtual void report_changes(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY, const struct timeval time=vrpn_ANALOG_NOW)
Send a report only if something has changed (for servers) Optionally, tell what time to stamp the val...
Definition vrpn_Analog.C:71
int register_autodeleted_handler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler, void *userdata, vrpn_int32 sender=vrpn_ANY_SENDER)
Registers a handler with the connection, and remembers to delete at destruction.
vrpn_Connection * d_connection
Connection that this object talks to.
void server_mainloop(void)
Handles functions that all servers should provide in their mainloop() (ping/pong, for example) Should...
vrpn_BaseClass(const char *name, vrpn_Connection *c=NULL)
Names the device and assigns or opens connection, calls registration methods.
virtual void report_changes(void)
vrpn_Button_Filter(const char *, vrpn_Connection *c=NULL)
vrpn_int32 num_buttons
Definition vrpn_Button.h:48
struct timeval timestamp
Definition vrpn_Button.h:49
virtual void report_changes(void)
unsigned char lastbuttons[vrpn_BUTTON_MAX_BUTTONS]
Definition vrpn_Button.h:46
unsigned char buttons[vrpn_BUTTON_MAX_BUTTONS]
Definition vrpn_Button.h:45
vrpn_CHProducts_Controller_Raw(vrpn_HidAcceptor *filter, const char *name, vrpn_Connection *c=0, vrpn_uint16 vendor=0, vrpn_uint16 product=0)
static int VRPN_CALLBACK on_last_disconnect(void *thisPtr, vrpn_HANDLERPARAM p)
virtual void decodePacket(size_t bytes, vrpn_uint8 *buffer)=0
void on_data_received(size_t bytes, vrpn_uint8 *buffer)
Derived class reimplements this callback.
static int VRPN_CALLBACK on_connect(void *thisPtr, vrpn_HANDLERPARAM p)
void decodePacket(size_t bytes, vrpn_uint8 *buffer)
vrpn_CHProducts_Fighterstick_USB(const char *name, vrpn_Connection *c=0)
virtual void mainloop(void)
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
Generic connection class not specific to the transport mechanism.
struct timeval timestamp
Definition vrpn_Dial.h:28
virtual void report(void)
Definition vrpn_Dial.C:82
vrpn_Dial(const char *name, vrpn_Connection *c=NULL)
Definition vrpn_Dial.C:8
vrpn_int32 num_dials
Definition vrpn_Dial.h:27
vrpn_uint16 product() const
Returns USB product ID of connected device May not contain valid if an already-open device was provid...
vrpn_HidInterface(vrpn_HidAcceptor *acceptor, vrpn_uint16 vendor=0, vrpn_uint16 product=0, hid_device *device=NULL)
Constructor If we already have a HID device from some other source, it can be passed and we'll take o...
virtual void update()
Polls the device buffers and causes on_data_received callbacks if appropriate You NEED to call this f...
vrpn_uint16 vendor() const
Returns USB vendor ID of connected device May not contain valid if an already-open device was provide...
Accepts any device with the given vendor and product IDs.
This structure is what is passed to a vrpn_Connection message callback.
#define VRPN_SUPPRESS_EMPTY_OBJECT_WARNING()
const char * vrpn_dropped_last_connection
const char * vrpn_got_connection
#define POLL_INTERVAL
Definition vrpn_IDEA.C:26
unsigned long vrpn_TimevalDuration(struct timeval endT, struct timeval startT)
Return number of microseconds between startT and endT.
#define vrpn_gettimeofday
Definition vrpn_Shared.h:99