vrpn 07.35
Virtual Reality Peripheral Network
Loading...
Searching...
No Matches
vrpn_Logitech_Controller_Raw.C
Go to the documentation of this file.
1// vrpn_Logitech_Controller_Raw.C: VRPN driver for Logitech (other than 3Dconnexion) 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 LOGITECH_VENDOR = 0x046d; // 3Dconnexion is made by Logitech
15static const vrpn_uint16 EXTREME_3D_PRO = 0xc215;
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
24static vrpn_float64 normalize_dpad(unsigned char up, unsigned char right, unsigned char down, unsigned char left)
25{
26 int x = 0;
27 int y = 0;
28 if (right)
29 {
30 x += 1;
31 }
32 if (left)
33 {
34 x -= 1;
35 }
36 if (up)
37 {
38 y += 1;
39 }
40 if (down)
41 {
42 y -= 1;
43 }
44 size_t index = ((x + 1) * 3) + (y + 1);
45 vrpn_float64 angles[] = {225, 270, 315, 180, -1, 0, 135, 90, 45};
46 return (angles[index]);
47}
48
49static void normalize_axis(const unsigned int value, const short deadzone, const vrpn_float64 scale, vrpn_float64& channel, int wordSize = 16)
50{
51 channel = (static_cast<float>(value) - (float) (1 << (wordSize - 1)));
52 if (fabs(channel) < (deadzone * 3 / 4))
53 {
54 channel = 0.0f;
55 }
56 else
57 {
58 channel /= (float) (1 << (wordSize - 1));
59 }
60 channel *= scale;
61 if (channel < -1.0) { channel = -1.0; }
62 if (channel > 1.0) { channel = 1.0; }
63}
64
65static 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)
66{
67 normalize_axis(x, deadzone, scale, channelX, wordSize);
68 normalize_axis(y, deadzone, scale, channelY, wordSize);
69}
70
72// Common base class
75 const char *name, vrpn_Connection *c, vrpn_uint16 vendor, vrpn_uint16 product) :
76 vrpn_BaseClass(name, c), vrpn_HidInterface(filter, vendor, product), _filter(filter)
77{
78 init_hid();
79}
80
82{
83 try {
84 delete _filter;
85 } catch (...) {
86 fprintf(stderr, "vrpn_Logitech_Controller_Raw::~vrpn_Logitech_Controller_Raw(): delete failed\n");
87 return;
88 }
89}
90
92{
93 // Get notifications when clients connect and disconnect
96}
97
98void vrpn_Logitech_Controller_Raw::on_data_received(size_t bytes, vrpn_uint8 *buffer)
99{
100 decodePacket(bytes, buffer);
101}
102
104{
105 return (0);
106}
107
109{
110 return (0);
111}
112
114// SideWinder Precision 2 Joystick
117vrpn_Logitech_Controller_Raw(new vrpn_HidProductAcceptor(LOGITECH_VENDOR, EXTREME_3D_PRO), name, c, LOGITECH_VENDOR, EXTREME_3D_PRO),
118 vrpn_Analog(name, c), vrpn_Button_Filter(name, c), vrpn_Dial(name, c)
119{
123
124 // Initialize the state of all the analogs, buttons, and dials
125 memset(buttons, 0, sizeof(buttons));
126 memset(lastbuttons, 0, sizeof(lastbuttons));
127 memset(channel, 0, sizeof(channel));
128 memset(last, 0, sizeof(last));
129}
130
132{
133 update();
135 struct timeval current_time;
136 vrpn_gettimeofday(&current_time, NULL);
137 if (vrpn_TimevalDuration(current_time, _timestamp) > POLL_INTERVAL)
138 {
139 _timestamp = current_time;
141
142 // Call the server_mainloop on our unique base class.
144 }
145}
146
147void vrpn_Logitech_Extreme_3D_Pro::report(vrpn_uint32 class_of_service)
148{
151 if (vrpn_Dial::num_dials > 0)
152 {
154 }
155
156 vrpn_Analog::report_changes(class_of_service);
158 if (vrpn_Dial::num_dials > 0)
159 {
161 }
162}
163
164void vrpn_Logitech_Extreme_3D_Pro::report_changes(vrpn_uint32 class_of_service)
165{
168 if (vrpn_Dial::num_dials > 0)
169 {
171 }
172
173 vrpn_Analog::report(class_of_service);
175 if (vrpn_Dial::num_dials > 0)
176 {
178 }
179}
180
181void vrpn_Logitech_Extreme_3D_Pro::decodePacket(size_t bytes, vrpn_uint8 *buffer)
182{
183 // SideWinder Precision 2 joystick
184
185 // Decode all full reports, each of which is 40 bytes long.
186 // Because there is only one type of report, the initial "0" report-type
187 // byte is removed by the HIDAPI driver.
188 /*
189? [0]: X-axis (left=00, right=ff)
190 [1]: Y-axis - lower byte (up=00, down=ff)
191 [2]: POV Hat high nibble (none=0x80, N=0x00, NE=0x10, ... NW=0x80), Y-axis upper nibble in low nibble of this byte
192 [3]: Z-rotate (left=00, right=ff)
193 [4]: buttons (bit flags: none=0x00, "1" (trigger)=0x01, "2"=0x02, "3"=0x04, ..., "8"=0x80
194 [5]: Slider (up=00, down=ff)
195 [6]: buttons (bit flags: none=0x00, "9"=0x01, "10"=0x02, "11"=0x04, "12"=0x08
196 */
197 // XXX Check to see that this works with HIDAPI, there may be two smaller reports.
198 if (bytes == 7)
199 {
200 unsigned int x, y;
201 x = buffer[0];
202 y = ((buffer[2] & 0x0f) << 8) + buffer[1];
203 normalize_axes(x, y, 0x16, 1.0f, channel[0], channel[1], 12);
204 normalize_axis(buffer[3], 0x12, 1.0f, channel[2], 8);
205 normalize_axis(buffer[5], 0x0e, 1.0f, channel[3], 8);
206
207 vrpn_uint8 value, mask;
208 value = buffer[4];
209 for (int btn = 0; btn < 8; btn++)
210 {
211 mask = static_cast<vrpn_uint8>(1 << (btn % 8));
212 buttons[btn] = ((value & mask) != 0);
213 }
214
215 value = buffer[6];
216 for (int btn = 0; btn < 4; btn++)
217 {
218 mask = static_cast<vrpn_uint8>(1 << (btn % 8));
219 buttons[btn + 12] = ((value & mask) != 0);
220 }
221
222 // Point of View Hat
223 buttons[8] = buttons[9] = buttons[10] = buttons[11] = 0;
224 switch (buffer[2] >> 4)
225 {
226 case 0: // up
227 buttons[8] = true;
228 break;
229 case 1:
230 buttons[8] = buttons[9] = true;
231 break;
232 case 2: // right
233 buttons[9] = true;
234 break;
235 case 3:
236 buttons[9] = buttons[10] = true;
237 break;
238 case 4: // down
239 buttons[10] = true;
240 break;
241 case 5:
242 buttons[10] = buttons[11] = true;
243 break;
244 case 6: // left
245 buttons[11] = true;
246 break;
247 case 7:
248 buttons[11] = buttons[8] = true;
249 break;
250 case 8:
251 default:
252 // nothing to do
253 break;
254 }
255 channel[4] = normalize_dpad(buttons[8], buttons[9], buttons[10], buttons[11]);
256 }
257 else
258 {
259 fprintf(stderr, "vrpn_Logitech_Extreme_3D_Pro: Found a corrupted report; # total bytes = %u\n", static_cast<unsigned>(bytes));
260 }
261}
262
263// End of VRPN_USE_HID
264#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)
Definition: vrpn_Button.C:383
vrpn_int32 num_buttons
Definition: vrpn_Button.h:48
struct timeval timestamp
Definition: vrpn_Button.h:49
virtual void report_changes(void)
Definition: vrpn_Button.C:423
unsigned char lastbuttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:46
unsigned char buttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:45
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.
static int VRPN_CALLBACK on_last_disconnect(void *thisPtr, vrpn_HANDLERPARAM p)
vrpn_Logitech_Controller_Raw(vrpn_HidAcceptor *filter, const char *name, vrpn_Connection *c=0, vrpn_uint16 vendor=0, vrpn_uint16 product=0)
void on_data_received(size_t bytes, vrpn_uint8 *buffer)
Derived class reimplements this callback.
virtual void decodePacket(size_t bytes, vrpn_uint8 *buffer)=0
static int VRPN_CALLBACK on_connect(void *thisPtr, vrpn_HANDLERPARAM p)
vrpn_Logitech_Extreme_3D_Pro(const char *name, vrpn_Connection *c=0)
void decodePacket(size_t bytes, vrpn_uint8 *buffer)
virtual void mainloop(void)
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
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.
Definition: vrpn_Shared.C:138
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:99