vrpn  07.33
Virtual Reality Peripheral Network
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
14 static const vrpn_uint16 CHPRODUCTS_VENDOR = 0x068e;
15 static const vrpn_uint16 FIGHTERSTICK_USB = 0x00f3;
16 
17 static 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 
25 static 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 
46 static 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 
62 static 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 
68 static vrpn_float64 normalize_trigger(unsigned int trigger)
69 {
70  // Filter out low-intensity signals
71  int value = trigger - 0x80;
72  return ((fabs(static_cast<double>(value)) < GAMEPAD_TRIGGER_THRESHOLD) ? 0.0f : (value * 2.0f / 255.0f));
73 }
74 
76 // Common base class
79  vrpn_HidInterface(filter)
80  , vrpn_BaseClass(name, c)
81  , _filter(filter)
82 {
83  init_hid();
84 }
85 
87 {
88  delete _filter;
89 }
90 
92 {
93  // Get notifications when clients connect and disconnect
96 }
97 
98 void vrpn_CHProducts_Controller_Raw::on_data_received(size_t bytes, vrpn_uint8 *buffer)
99 {
100  decodePacket(bytes, buffer);
101 }
102 
104 {
105  vrpn_CHProducts_Controller_Raw* me = static_cast<vrpn_CHProducts_Controller_Raw*>(thisPtr);
106  return (0);
107 }
108 
110 {
111  vrpn_CHProducts_Controller_Raw* me = static_cast<vrpn_CHProducts_Controller_Raw*>(thisPtr);
112  return (0);
113 }
114 
116 // ST290 Pro Joystick
119  vrpn_CHProducts_Controller_Raw(_filter = new vrpn_HidProductAcceptor(CHPRODUCTS_VENDOR, FIGHTERSTICK_USB), name, c),
120  vrpn_Button_Filter(name, c), vrpn_Analog(name, c), vrpn_Dial(name, c)
121 {
125 
126  // Initialize the state of all the analogs, buttons, and dials
127  memset(buttons, 0, sizeof(buttons));
128  memset(lastbuttons, 0, sizeof(lastbuttons));
129  memset(channel, 0, sizeof(channel));
130  memset(last, 0, sizeof(last));
131 }
132 
134 {
135  update();
136  server_mainloop();
137  struct timeval current_time;
138  vrpn_gettimeofday(&current_time, NULL);
139  if (vrpn_TimevalDuration(current_time, _timestamp) > POLL_INTERVAL)
140  {
141  _timestamp = current_time;
142  report_changes();
143 
146  if (vrpn_Dial::num_dials > 0)
147  {
149  }
150  }
151 }
152 
153 void vrpn_CHProducts_Fighterstick_USB::report(vrpn_uint32 class_of_service)
154 {
157  if (vrpn_Dial::num_dials > 0)
158  {
160  }
161 
162  vrpn_Analog::report_changes(class_of_service);
164  if (vrpn_Dial::num_dials > 0)
165  {
167  }
168 }
169 
170 void vrpn_CHProducts_Fighterstick_USB::report_changes(vrpn_uint32 class_of_service)
171 {
174  if (vrpn_Dial::num_dials > 0)
175  {
177  }
178 
179  vrpn_Analog::report(class_of_service);
181  if (vrpn_Dial::num_dials > 0)
182  {
184  }
185 }
186 
187 void vrpn_CHProducts_Fighterstick_USB::decodePacket(size_t bytes, vrpn_uint8 *buffer)
188 {
189  // Fighterstick USB joystick
190 
191  // Decode all full reports, each of which is 6 bytes long.
192  // Because there is only one type of report, the initial "0" report-type
193  // byte is removed by the HIDAPI driver.
194  /*
195  [0]: X-axis (left=00, right=ff, center=80)
196  [1]: Y-axis (up=00, down=ff, center=80)
197  [2]: throttle wheel (up=00, down=ff)
198  [3]: buttons high nibble: 0x10=trigger, 0x20=top red, 0x40=upper index red (toggles buttons 17-19), 0x80=pinky red,
199  - - low nibble 8-way POV hat upper-right on top: none=0x00, N=0x01, NE=0x02, ... NW=0x08
200  [4]: high nibble 4-way hat #2 (lower-right on top): none=0x00, N=0x10, E=0x20, S=0x40, W=0x80
201  - - low nibble 4-way hat #1 (left on top): none=0x00, N=0x01, E=0x02, S=0x04, W=0x08
202  [5]: upper nibble mode bits: 0x10=green, 0x20=red, 0x40=yellow, 0x80=<not used>
203  - - low nibble 4-way hat #3 (thumb): none=0x00, N=0x01, E=0x02, S=0x04, W=0x08
204  */
205  // XXX Check to see that this works with HIDAPI, there may be two smaller reports.
206  if (bytes == 6)
207  {
208  normalize_axes(buffer[0], buffer[1], 0x08, 1.0f, channel[0], channel[1], 8);
209  normalize_axis(buffer[2], 0x08, 1.0f, channel[2], 8);
210 
211  vrpn_uint8 value, mask;
212  value = (buffer[3] >> 4);
213  for (int btn = 0; btn < 4; btn++)
214  {
215  mask = static_cast<vrpn_uint8>(1 << (btn % 8));
216  buttons[btn] = ((value & mask) != 0);
217  }
218 
219  // Point of View Hat
220  buttons[4] = buttons[5] = buttons[6] = buttons[7] = 0;
221  switch (buffer[3] & 0x0f)
222  {
223  case 1: // up
224  buttons[4] = true;
225  break;
226  case 2:
227  buttons[4] = buttons[5] = true;
228  break;
229  case 3: // right
230  buttons[5] = true;
231  break;
232  case 4:
233  buttons[5] = buttons[6] = true;
234  break;
235  case 5: // down
236  buttons[6] = true;
237  break;
238  case 6:
239  buttons[6] = buttons[7] = true;
240  break;
241  case 7: // left
242  buttons[7] = true;
243  break;
244  case 8:
245  buttons[7] = buttons[4] = true;
246  break;
247  case 0:
248  default:
249  // nothing to do
250  break;
251  }
252  channel[3] = normalize_dpad(buttons[4], buttons[5], buttons[6], buttons[7]);
253 
254  // 4-way Hat #2
255  buttons[8] = buttons[9] = buttons[10] = buttons[11] = 0;
256  switch (buffer[4] >> 4)
257  {
258  case 1: // up
259  buttons[8] = true;
260  break;
261  case 2: // right
262  buttons[9] = true;
263  break;
264  case 4: // down
265  buttons[10] = true;
266  break;
267  case 8: // left
268  buttons[11] = true;
269  break;
270  case 0:
271  default:
272  // nothing to do
273  break;
274  }
275  channel[4] = normalize_dpad(buttons[8], buttons[9], buttons[10], buttons[11]);
276  // 4-way Hat #1
277  buttons[12] = buttons[13] = buttons[14] = buttons[15] = 0;
278  switch (buffer[4] & 0x0f)
279  {
280  case 1: // up
281  buttons[12] = true;
282  break;
283  case 2: // right
284  buttons[13] = true;
285  break;
286  case 4: // down
287  buttons[14] = true;
288  break;
289  case 8: // left
290  buttons[15] = true;
291  break;
292  case 0:
293  default:
294  // nothing to do
295  break;
296  }
297  channel[5] = normalize_dpad(buttons[12], buttons[13], buttons[14], buttons[15]);
298 
299  // mode
300  // keep pseudo-button pressed to indicate mode
301  //buttons[16] = buttons[17] = buttons[18] = buttons[19] = 0;
302  switch (buffer[5] >> 4)
303  {
304  case 1: // green
305  buttons[16] = true;
306  buttons[17] = buttons[18] = false;
307  break;
308  case 2: // red
309  buttons[17] = true;
310  buttons[16] = buttons[18] = false;
311  break;
312  case 4: // yellow
313  buttons[18] = true;
314  buttons[16] = buttons[17] = false;
315  break;
316 /*
317  case 8: // none
318  buttons[19] = true;
319  break;
320 */
321  case 0:
322  default:
323  // nothing to do
324  break;
325  }
326  if (buttons[16] || buttons[17] || buttons[18] || buttons[19])
327  {
328  channel[6] = (normalize_dpad(buttons[16], buttons[17], buttons[18], buttons[19]) / 90.0f) + 1.0f;
329  }
330  // 4-way Hat #3
331  buttons[20] = buttons[21] = buttons[22] = buttons[23] = 0;
332  switch (buffer[5] & 0x0f)
333  {
334  case 1: // up
335  buttons[20] = true;
336  break;
337  case 2: // right
338  buttons[21] = true;
339  break;
340  case 4: // down
341  buttons[22] = true;
342  break;
343  case 8: // left
344  buttons[23] = true;
345  break;
346  case 0:
347  default:
348  // nothing to do
349  break;
350  }
351  channel[7] = normalize_dpad(buttons[20], buttons[21], buttons[22], buttons[23]);
352  }
353  else
354  {
355  fprintf(stderr, "vrpn_CHProducts_Fighterstick_USB: Found a corrupted report; # total bytes = %u\n", static_cast<unsigned>(bytes));
356  }
357 }
358 
359 // End of VRPN_USE_HID
360 #endif
vrpn_CHProducts_Controller_Raw.h
vrpn_CHProducts_Controller_Raw::decodePacket
virtual void decodePacket(size_t bytes, vrpn_uint8 *buffer)=0
vrpn_BaseClassUnique::register_autodeleted_handler
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.
Definition: vrpn_BaseClass.C:503
vrpn_Dial::report
virtual void report(void)
Definition: vrpn_Dial.C:82
vrpn_Button::report_changes
virtual void report_changes(void)
Definition: vrpn_Button.C:422
vrpn_got_connection
const char * vrpn_got_connection
Definition: vrpn_Connection.C:185
vrpn_CHProducts_Controller_Raw::~vrpn_CHProducts_Controller_Raw
virtual ~vrpn_CHProducts_Controller_Raw(void)
Definition: vrpn_CHProducts_Controller_Raw.C:86
vrpn_TimevalDuration
unsigned long vrpn_TimevalDuration(struct timeval endT, struct timeval startT)
Return number of microseconds between startT and endT.
Definition: vrpn_Shared.C:129
vrpn_Button_Filter::report_changes
virtual void report_changes(void)
Definition: vrpn_Button.C:382
vrpn_Analog::channel
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:38
vrpn_CHProducts_Controller_Raw::_timestamp
struct timeval _timestamp
Definition: vrpn_CHProducts_Controller_Raw.h:40
vrpn_HidInterface
Definition: vrpn_HumanInterface.h:68
vrpn_dropped_last_connection
const char * vrpn_dropped_last_connection
Definition: vrpn_Connection.C:187
vrpn_Analog::report
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
vrpn_CHProducts_Fighterstick_USB::mainloop
virtual void mainloop(void)
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
Definition: vrpn_CHProducts_Controller_Raw.C:133
vrpn_Analog
Definition: vrpn_Analog.h:28
vrpn_Analog::timestamp
struct timeval timestamp
Definition: vrpn_Analog.h:41
vrpn_CHProducts_Controller_Raw::vrpn_CHProducts_Controller_Raw
vrpn_CHProducts_Controller_Raw(vrpn_HidAcceptor *filter, const char *name, vrpn_Connection *c=0)
Definition: vrpn_CHProducts_Controller_Raw.C:78
vrpn_CHProducts_Controller_Raw::on_data_received
void on_data_received(size_t bytes, vrpn_uint8 *buffer)
Derived class reimplements this callback.
Definition: vrpn_CHProducts_Controller_Raw.C:98
vrpn_HidInterface::update
virtual void update()
Polls the device buffers and causes on_data_received callbacks if appropriate You NEED to call this f...
Definition: vrpn_HumanInterface.C:140
vrpn_HidAcceptor
Definition: vrpn_HumanInterface.h:54
vrpn_Button::num_buttons
vrpn_int32 num_buttons
Definition: vrpn_Button.h:47
POLL_INTERVAL
#define POLL_INTERVAL
Definition: vrpn_IDEA.C:26
vrpn_CHProducts_Controller_Raw::_filter
vrpn_HidAcceptor * _filter
Definition: vrpn_CHProducts_Controller_Raw.h:41
vrpn_Button::buttons
unsigned char buttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:44
vrpn_BaseClassUnique::d_connection
vrpn_Connection * d_connection
Connection that this object talks to.
Definition: vrpn_BaseClass.h:224
vrpn_Connection::register_message_type
virtual vrpn_int32 register_message_type(const char *name)
Definition: vrpn_Connection.C:5074
vrpn_Dial
Definition: vrpn_Dial.h:21
vrpn_HANDLERPARAM
This structure is what is passed to a vrpn_Connection message callback.
Definition: vrpn_Connection.h:44
vrpn_CHProducts_Controller_Raw::on_last_disconnect
static int VRPN_CALLBACK on_last_disconnect(void *thisPtr, vrpn_HANDLERPARAM p)
Definition: vrpn_CHProducts_Controller_Raw.C:103
vrpn_HidProductAcceptor
Accepts any device with the given vendor and product IDs.
Definition: vrpn_HumanInterface.h:150
GAMEPAD_TRIGGER_THRESHOLD
#define GAMEPAD_TRIGGER_THRESHOLD
Definition: vrpn_CHProducts_Controller_Raw.C:19
vrpn_Button::timestamp
struct timeval timestamp
Definition: vrpn_Button.h:48
vrpn_Connection
Generic connection class not specific to the transport mechanism.
Definition: vrpn_Connection.h:510
vrpn_Analog::num_channel
vrpn_int32 num_channel
Definition: vrpn_Analog.h:40
vrpn_gettimeofday
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
vrpn_Button::lastbuttons
unsigned char lastbuttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:45
vrpn_CHProducts_Controller_Raw::init_hid
void init_hid(void)
Definition: vrpn_CHProducts_Controller_Raw.C:91
vrpn_Analog::last
vrpn_float64 last[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:39
vrpn_CHProducts_Controller_Raw
Definition: vrpn_CHProducts_Controller_Raw.h:25
vrpn_CHProducts_Controller_Raw::on_connect
static int VRPN_CALLBACK on_connect(void *thisPtr, vrpn_HANDLERPARAM p)
Definition: vrpn_CHProducts_Controller_Raw.C:109
vrpn_CHProducts_Fighterstick_USB::decodePacket
void decodePacket(size_t bytes, vrpn_uint8 *buffer)
Definition: vrpn_CHProducts_Controller_Raw.C:187
vrpn_Analog::report_changes
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
VRPN_SUPPRESS_EMPTY_OBJECT_WARNING
#define VRPN_SUPPRESS_EMPTY_OBJECT_WARNING()
Definition: vrpn_Configure.h:495
vrpn_Dial::num_dials
vrpn_int32 num_dials
Definition: vrpn_Dial.h:27
vrpn_Dial::timestamp
struct timeval timestamp
Definition: vrpn_Dial.h:28
vrpn_CHProducts_Fighterstick_USB::vrpn_CHProducts_Fighterstick_USB
vrpn_CHProducts_Fighterstick_USB(const char *name, vrpn_Connection *c=0)
Definition: vrpn_CHProducts_Controller_Raw.C:118
vrpn_BaseClassUnique::server_mainloop
void server_mainloop(void)
Handles functions that all servers should provide in their mainloop() (ping/pong, for example) Should...
Definition: vrpn_BaseClass.C:603
vrpn_BaseClass
Class from which all user-level (and other) classes that communicate with vrpn_Connections should der...
Definition: vrpn_BaseClass.h:313
vrpn_Button_Filter
All button servers should derive from this class, which provides the ability to turn any of the butto...
Definition: vrpn_Button.h:65