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)
74 , vrpn_HidInterface(filter, vendor, product)
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
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
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...
Class from which all user-level (and other) classes that communicate with vrpn_Connections should der...
All button servers should derive from this class, which provides the ability to turn any of the butto...
Definition vrpn_Button.h:66
virtual void report_changes(void)
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.
virtual vrpn_int32 register_message_type(const char *name)
struct timeval timestamp
Definition vrpn_Dial.h:28
virtual void report(void)
Definition vrpn_Dial.C:82
vrpn_int32 num_dials
Definition vrpn_Dial.h:27
virtual void update()
Polls the device buffers and causes on_data_received callbacks if appropriate You NEED to call this f...
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