vrpn  07.33
Virtual Reality Peripheral Network
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
14 static const vrpn_uint16 LOGITECH_VENDOR = 0x046d; // 3Dconnexion is made by Logitech
15 static const vrpn_uint16 EXTREME_3D_PRO = 0xc215;
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 static 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 
49 static 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 
65 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)
66 {
67  normalize_axis(x, deadzone, scale, channelX, wordSize);
68  normalize_axis(y, deadzone, scale, channelY, wordSize);
69 }
70 
71 static vrpn_float64 normalize_trigger(unsigned int trigger)
72 {
73  // Filter out low-intensity signals
74  int value = trigger - 0x80;
75  return ((fabs(static_cast<double>(value)) < GAMEPAD_TRIGGER_THRESHOLD) ? 0.0f : (value * 2.0f / 255.0f));
76 }
77 
79 // Common base class
82  vrpn_HidInterface(filter), vrpn_BaseClass(name, c), _filter(filter)
83 {
84  init_hid();
85 }
86 
88 {
89  delete _filter;
90 }
91 
93 {
94  // Get notifications when clients connect and disconnect
97 }
98 
99 void vrpn_Logitech_Controller_Raw::on_data_received(size_t bytes, vrpn_uint8 *buffer)
100 {
101  decodePacket(bytes, buffer);
102 }
103 
105 {
106  vrpn_Logitech_Controller_Raw* me = static_cast<vrpn_Logitech_Controller_Raw*>(thisPtr);
107  return (0);
108 }
109 
111 {
112  vrpn_Logitech_Controller_Raw* me = static_cast<vrpn_Logitech_Controller_Raw*>(thisPtr);
113  return (0);
114 }
115 
117 // SideWinder Precision 2 Joystick
120  vrpn_Logitech_Controller_Raw(_filter = new vrpn_HidProductAcceptor(LOGITECH_VENDOR, EXTREME_3D_PRO), name, c),
121  vrpn_Button_Filter(name, c), vrpn_Analog(name, c), vrpn_Dial(name, c)
122 {
126 
127  // Initialize the state of all the analogs, buttons, and dials
128  memset(buttons, 0, sizeof(buttons));
129  memset(lastbuttons, 0, sizeof(lastbuttons));
130  memset(channel, 0, sizeof(channel));
131  memset(last, 0, sizeof(last));
132 }
133 
135 {
136  update();
137  server_mainloop();
138  struct timeval current_time;
139  vrpn_gettimeofday(&current_time, NULL);
140  if (vrpn_TimevalDuration(current_time, _timestamp) > POLL_INTERVAL)
141  {
142  _timestamp = current_time;
143  report_changes();
144 
147  if (vrpn_Dial::num_dials > 0)
148  {
150  }
151  }
152 }
153 
154 void vrpn_Logitech_Extreme_3D_Pro::report(vrpn_uint32 class_of_service)
155 {
158  if (vrpn_Dial::num_dials > 0)
159  {
161  }
162 
163  vrpn_Analog::report_changes(class_of_service);
165  if (vrpn_Dial::num_dials > 0)
166  {
168  }
169 }
170 
171 void vrpn_Logitech_Extreme_3D_Pro::report_changes(vrpn_uint32 class_of_service)
172 {
175  if (vrpn_Dial::num_dials > 0)
176  {
178  }
179 
180  vrpn_Analog::report(class_of_service);
182  if (vrpn_Dial::num_dials > 0)
183  {
185  }
186 }
187 
188 void vrpn_Logitech_Extreme_3D_Pro::decodePacket(size_t bytes, vrpn_uint8 *buffer)
189 {
190  // SideWinder Precision 2 joystick
191 
192  // Decode all full reports, each of which is 40 bytes long.
193  // Because there is only one type of report, the initial "0" report-type
194  // byte is removed by the HIDAPI driver.
195  /*
196 ? [0]: X-axis (left=00, right=ff)
197  [1]: Y-axis - lower byte (up=00, down=ff)
198  [2]: POV Hat high nibble (none=0x80, N=0x00, NE=0x10, ... NW=0x80), Y-axis upper nibble in low nibble of this byte
199  [3]: Z-rotate (left=00, right=ff)
200  [4]: buttons (bit flags: none=0x00, "1" (trigger)=0x01, "2"=0x02, "3"=0x04, ..., "8"=0x80
201  [5]: Slider (up=00, down=ff)
202  [6]: buttons (bit flags: none=0x00, "9"=0x01, "10"=0x02, "11"=0x04, "12"=0x08
203  */
204  // XXX Check to see that this works with HIDAPI, there may be two smaller reports.
205  if (bytes == 7)
206  {
207  unsigned int x, y;
208  x = buffer[0];
209  y = ((buffer[2] & 0x0f) << 8) + buffer[1];
210  normalize_axes(x, y, 0x16, 1.0f, channel[0], channel[1], 12);
211  normalize_axis(buffer[3], 0x12, 1.0f, channel[2], 8);
212  normalize_axis(buffer[5], 0x0e, 1.0f, channel[3], 8);
213 
214  vrpn_uint8 value, mask;
215  value = buffer[4];
216  for (int btn = 0; btn < 8; btn++)
217  {
218  mask = static_cast<vrpn_uint8>(1 << (btn % 8));
219  buttons[btn] = ((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_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_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_Logitech_Controller_Raw.h
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_Logitech_Controller_Raw::on_last_disconnect
static int VRPN_CALLBACK on_last_disconnect(void *thisPtr, vrpn_HANDLERPARAM p)
Definition: vrpn_Logitech_Controller_Raw.C:104
vrpn_Logitech_Controller_Raw::on_connect
static int VRPN_CALLBACK on_connect(void *thisPtr, vrpn_HANDLERPARAM p)
Definition: vrpn_Logitech_Controller_Raw.C:110
vrpn_Logitech_Controller_Raw::~vrpn_Logitech_Controller_Raw
virtual ~vrpn_Logitech_Controller_Raw(void)
Definition: vrpn_Logitech_Controller_Raw.C:87
vrpn_Analog
Definition: vrpn_Analog.h:28
vrpn_Analog::timestamp
struct timeval timestamp
Definition: vrpn_Analog.h:41
vrpn_Logitech_Controller_Raw
Definition: vrpn_Logitech_Controller_Raw.h:25
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
vrpn_Logitech_Controller_Raw::_filter
vrpn_HidAcceptor * _filter
Definition: vrpn_Logitech_Controller_Raw.h:41
POLL_INTERVAL
#define POLL_INTERVAL
Definition: vrpn_IDEA.C:26
vrpn_Button::buttons
unsigned char buttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:44
vrpn_Logitech_Controller_Raw::vrpn_Logitech_Controller_Raw
vrpn_Logitech_Controller_Raw(vrpn_HidAcceptor *filter, const char *name, vrpn_Connection *c=0)
Definition: vrpn_Logitech_Controller_Raw.C:81
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_Logitech_Controller_Raw::init_hid
void init_hid(void)
Definition: vrpn_Logitech_Controller_Raw.C:92
vrpn_HidProductAcceptor
Accepts any device with the given vendor and product IDs.
Definition: vrpn_HumanInterface.h:150
vrpn_Button::timestamp
struct timeval timestamp
Definition: vrpn_Button.h:48
vrpn_Logitech_Controller_Raw::on_data_received
void on_data_received(size_t bytes, vrpn_uint8 *buffer)
Derived class reimplements this callback.
Definition: vrpn_Logitech_Controller_Raw.C:99
vrpn_Connection
Generic connection class not specific to the transport mechanism.
Definition: vrpn_Connection.h:510
vrpn_Logitech_Extreme_3D_Pro::decodePacket
void decodePacket(size_t bytes, vrpn_uint8 *buffer)
Definition: vrpn_Logitech_Controller_Raw.C:188
vrpn_Analog::num_channel
vrpn_int32 num_channel
Definition: vrpn_Analog.h:40
vrpn_Logitech_Extreme_3D_Pro::mainloop
virtual void mainloop(void)
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
Definition: vrpn_Logitech_Controller_Raw.C:134
vrpn_gettimeofday
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
GAMEPAD_TRIGGER_THRESHOLD
#define GAMEPAD_TRIGGER_THRESHOLD
Definition: vrpn_Logitech_Controller_Raw.C:19
vrpn_Button::lastbuttons
unsigned char lastbuttons[vrpn_BUTTON_MAX_BUTTONS]
Definition: vrpn_Button.h:45
vrpn_Logitech_Controller_Raw::decodePacket
virtual void decodePacket(size_t bytes, vrpn_uint8 *buffer)=0
vrpn_Analog::last
vrpn_float64 last[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:39
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_Logitech_Extreme_3D_Pro::vrpn_Logitech_Extreme_3D_Pro
vrpn_Logitech_Extreme_3D_Pro(const char *name, vrpn_Connection *c=0)
Definition: vrpn_Logitech_Controller_Raw.C:119
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_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
vrpn_Logitech_Controller_Raw::_timestamp
struct timeval _timestamp
Definition: vrpn_Logitech_Controller_Raw.h:40