vrpn  07.33
Virtual Reality Peripheral Network
vrpn_3DConnexion.C
Go to the documentation of this file.
1 // vrpn_3DConnexion.C: VRPN driver for 3DConnexion
2 // Space Navigator, Space Traveler, Space Explorer, Space Mouse, Spaceball 5000
3 #include <string.h> // for memset
4 
5 #include "vrpn_3DConnexion.h"
6 #include "vrpn_BaseClass.h" // for ::vrpn_TEXT_WARNING
7 
8 // There is a non-HID Linux-based driver for this device that has a capability
9 // not implemented in the HID interface. It uses the input.h interface.
10 #if defined(linux) && !defined(VRPN_USE_HID)
11 #define VRPN_USING_3DCONNEXION_EVENT_IFACE
12 #include <linux/input.h>
13 #include <stdlib.h> // for malloc, free, etc
14 #include <unistd.h> // for write, etc
15 #endif
16 
17 typedef struct input_devinfo {
18  vrpn_uint16 bustype;
19  vrpn_uint16 vendor;
20  vrpn_uint16 product;
21  vrpn_uint16 version;
22 } XXX_should_have_been_in_system_includes;
23 
24 // USB vendor and product IDs for the models we support
25 static const vrpn_uint16 vrpn_3DCONNEXION_VENDOR = 0x046d; //1133; // 3Dconnexion is made by Logitech
26 static const vrpn_uint16 vrpn_SPACEMOUSEWIRELESS_VENDOR = 9583; // Made by a different vendor...
27 static const vrpn_uint16 vrpn_3DCONNEXION_TRAVELER = 50723;
28 static const vrpn_uint16 vrpn_3DCONNEXION_NAVIGATOR = 50726;
29 static const vrpn_uint16 vrpn_3DCONNEXION_NAVIGATOR_FOR_NOTEBOOKS = 0xc628; // 50728;
30 static const vrpn_uint16 vrpn_3DCONNEXION_SPACEEXPLORER = 0xc627; // 50727
31 static const vrpn_uint16 vrpn_3DCONNEXION_SPACEMOUSE = 50691;
32 static const vrpn_uint16 vrpn_3DCONNEXION_SPACEMOUSEPRO = 50731;
33 static const vrpn_uint16 vrpn_3DCONNEXION_SPACEMOUSEWIRELESS = 50735;
34 static const vrpn_uint16 vrpn_3DCONNEXION_SPACEBALL5000 = 0xc621; // 50721;
35 static const vrpn_uint16 vrpn_3DCONNEXION_SPACEPILOT = 0xc625;
36 
38  const char *name, vrpn_Connection *c)
39  : vrpn_Button_Filter(name, c)
40  , vrpn_Analog(name, c)
41 #if defined(VRPN_USE_HID)
42  , vrpn_HidInterface(filter)
43 #endif
44  , _filter(filter)
45 {
48 
49  // Initialize the state of all the analogs and buttons
50  memset(buttons, 0, sizeof(buttons));
51  memset(lastbuttons, 0, sizeof(lastbuttons));
52  memset(channel, 0, sizeof(channel));
53  memset(last, 0, sizeof(last));
54 
55 // There is a non-HID Linux-based driver for this device that has a capability
56 // not implemented in the HID interface. It is implemented using the Event
57 // interface.
58 #if defined(VRPN_USING_3DCONNEXION_EVENT_IFACE)
59  // Use the Event interface to open devices looking for the one
60  // we want. Call the acceptor with all the devices we find
61  // until we get one that we want.
62  fd = -1;
63  FILE *f;
64  int i = 0;
65 
66  // try to autodetect the device
67  char *fname = (char *)malloc(1000*sizeof(char));
68  while(i < 256) {
69  sprintf(fname, "/dev/input/event%d", i++);
70  f = fopen(fname, "r+b");
71  if(f) {
72  // We got an active device. Fill in its values and see if it
73  // is acceptable to the filter.
74  struct input_devinfo ID;
75  ioctl(fileno(f), EVIOCGID, &ID);
76  vrpn_HIDDEVINFO info;
77  info.product = ID.product;
78  info.vendor = ID.vendor;
79  if (_filter->accept(info)) {
80  fd = fileno(f);
81  set_led(1);
82  break;
83  } else {
84  fclose(f);
85  f = NULL;
86  }
87  }
88  }
89 
90  if(!f) {
91  perror("Could not open the device");
92  exit(1);
93  }
94 
95  fclose(f);
96  free(fname);
97 
98  // turn the LED on
99  set_led(1);
100 #endif
101 }
102 
104 {
105 #if defined(VRPN_USING_3DCONNEXION_EVENT_IFACE)
106  set_led(0);
107 #endif
108  delete _filter;
109 }
110 
111 #if defined(VRPN_USE_HID)
112 void vrpn_3DConnexion::on_data_received(size_t bytes, vrpn_uint8 *buffer)
113 {
114  decodePacket(bytes, buffer);
115 }
116 #endif
117 
119 {
120 #if defined(VRPN_USE_HID)
121  // Full reports are 7 bytes long.
122  // XXX If we get a 2-byte report mixed in, then something is going to get
123  // truncated.
124  update();
125 #elif defined(VRPN_USING_3DCONNEXION_EVENT_IFACE)
126  struct timeval zerotime;
127  fd_set fdset;
128  struct input_event ev;
129  int i;
130 
131  zerotime.tv_sec = 0;
132  zerotime.tv_usec = 0;
133 
134  FD_ZERO(&fdset); /* clear fdset */
135  FD_SET(fd, &fdset); /* include fd in fdset */
136  int moreData = 0;
137  do {
138  vrpn_noint_select(fd + 1, &fdset, NULL, NULL, &zerotime);
139  moreData = 0;
140  if (FD_ISSET(fd, &fdset)) {
141  moreData = 1;
142  if (vrpn_noint_block_read(fd, reinterpret_cast<char*>(&ev), sizeof(struct input_event)) != sizeof(struct input_event)) {
143  send_text_message("Error reading from vrpn_3DConnexion", vrpn_Analog::timestamp, vrpn_TEXT_ERROR);
145  return;
146  }
147  switch (ev.type) {
148  case EV_KEY: // button movement
149  vrpn_gettimeofday((timeval *)&this->vrpn_Button::timestamp, NULL);
150  buttons[ev.code & 0x0ff] = ev.value;
151  break;
152 
153  case EV_REL: // axis movement
154  case EV_ABS: // new kernels send more logical _ABS instead of _REL
155  vrpn_gettimeofday((timeval *)&this->vrpn_Analog::timestamp, NULL);
156  // Convert from short to int to avoid a short/double conversion
157  // bug in GCC 3.2.
158  i = ev.value;
159  channel[ev.code] = static_cast<double>(i)/400.0;
160  break;
161 
162  default:
163  break;
164  }
165  }
166  report_changes();
167  } while (moreData == 1);
168 #endif
169 
170  server_mainloop();
172 }
173 
174 void vrpn_3DConnexion::report_changes(vrpn_uint32 class_of_service)
175 {
178 
179  vrpn_Analog::report_changes(class_of_service);
181 }
182 
183 void vrpn_3DConnexion::report(vrpn_uint32 class_of_service)
184 {
187 
188  vrpn_Analog::report(class_of_service);
190 }
191 
192 #if defined(linux) && !defined(VRPN_USE_HID)
193 int vrpn_3DConnexion::set_led(int led_state)
194 {
195  struct input_event event;
196  int ret;
197 
198  event.type = EV_LED;
199  event.code = LED_MISC;
200  event.value = led_state;
201 
202  ret = write(fd, &event, sizeof(struct input_event));
203  if (ret < 0) {
204  perror ("setting led state failed");
205  }
206  return ret < static_cast<int>(sizeof(struct input_event));
207 }
208 #endif
209 
210 #if defined(VRPN_USE_HID)
211 void vrpn_3DConnexion::decodePacket(size_t bytes, vrpn_uint8 *buffer)
212 {
213  // Force 'small' buffers (ie button under linux - 3 bytes - and apple - 2 bytes - into 7 bytes
214  // so we get through the report loop once. XXX Problem: this is skipping 7 bytes per report
215  // regardless of how many bytes were in the report. This is going to get us into trouble for
216  // multi-report packets. Instead, we should go until we've parsed all characters and add the
217  // number of characters parsed each time rather than a constant 7 reports.
218  if(bytes<7) bytes=7;
219  if (bytes > 7) {
220  fprintf(stderr, "vrpn_3DConnexion::decodePacket(): Long packet (%d bytes), may mis-parse\n",
221  static_cast<int>(bytes));
222  }
223  // Decode all full reports.
224  // Full reports for all of the pro devices are 7 bytes long (the first
225  // byte is the report type, because this device has multiple ones the
226  // HIDAPI library leaves it in the report).
227  for (size_t i = 0; i < bytes / 7; i++) {
228  vrpn_uint8 *report = buffer + (i * 7);
229 
230  // There are three types of reports. Parse whichever type
231  // this is.
232  char report_type = report[0];
233  vrpn_uint8 *bufptr = &report[1];
234  const float scale = 1.0f/400.0f;
235  switch (report_type) {
236  // Report types 1 and 2 come one after the other. Each seems
237  // to change when the puck is moved. It looks like each pair
238  // of values records a signed value for one channel; report
239  // type 1 is translation and report type 2 is rotation.
240  // The minimum and maximum values seem to vary somewhat.
241  // They all seem to be able to get over 400, so we scale
242  // by 400 and then clamp to (-1..1).
243  // The first byte is the low-order byte and the second is the
244  // high-order byte.
245  case 1:
246  channel[0] = vrpn_unbuffer_from_little_endian<vrpn_int16>(bufptr) * scale;
247  if (channel[0] < -1.0) { channel[0] = -1.0; }
248  if (channel[0] > 1.0) { channel[0] = 1.0; }
249  channel[1] = vrpn_unbuffer_from_little_endian<vrpn_int16>(bufptr) * scale;
250  if (channel[1] < -1.0) { channel[1] = -1.0; }
251  if (channel[1] > 1.0) { channel[1] = 1.0; }
252  channel[2] = vrpn_unbuffer_from_little_endian<vrpn_int16>(bufptr) * scale;
253  if (channel[2] < -1.0) { channel[2] = -1.0; }
254  if (channel[2] > 1.0) { channel[2] = 1.0; }
255  break;
256 
257  case 2:
258  channel[3] = vrpn_unbuffer_from_little_endian<vrpn_int16>(bufptr) * scale;
259  if (channel[3] < -1.0) { channel[3] = -1.0; }
260  if (channel[3] > 1.0) { channel[3] = 1.0; }
261  channel[4] = vrpn_unbuffer_from_little_endian<vrpn_int16>(bufptr) * scale;
262  if (channel[4] < -1.0) { channel[4] = -1.0; }
263  if (channel[4] > 1.0) { channel[4] = 1.0; }
264  channel[5] = vrpn_unbuffer_from_little_endian<vrpn_int16>(bufptr) * scale;
265  if (channel[5] < -1.0) { channel[5] = -1.0; }
266  if (channel[5] > 1.0) { channel[5] = 1.0; }
267  break;
268 
269  case 3: { // Button report
270  int btn;
271 
272  // Button reports are encoded as bits in the first 2 bytes
273  // after the type. There can be more than one byte if there
274  // are more than 8 buttons such as on SpaceExplorer or SpaceBall5000.
275  // If 8 or less, we don't look at 2nd byte.
276  // SpaceExplorer buttons are (for example):
277  // Name Number
278  // 1 0
279  // 2 1
280  // T 2
281  // L 3
282  // R 4
283  // F 5
284  // ESC 6
285  // ALT 7
286  // SHIFT 8
287  // CTRL 9
288  // FIT 10
289  // PANEL 11
290  // + 12
291  // - 13
292  // 2D 14
293 
294  for (btn = 0; btn < vrpn_Button::num_buttons; btn++) {
295  vrpn_uint8 *location, mask;
296  location = report + 1 + (btn / 8);
297  mask = 1 << (btn % 8);
298  buttons[btn] = ( (*location) & mask) != 0;
299  }
300  break;
301  }
302 
303  default:
305  send_text_message("Unknown report type", _timestamp, vrpn_TEXT_WARNING);
306  }
307  // Report this event before parsing the next.
308  report_changes();
309  }
310 }
311 #endif
312 
314  : vrpn_3DConnexion(_filter = new vrpn_HidProductAcceptor(vrpn_3DCONNEXION_VENDOR, vrpn_3DCONNEXION_NAVIGATOR), 2, name, c)
315 {
316 }
317 
319  : vrpn_3DConnexion(_filter = new vrpn_HidProductAcceptor(vrpn_3DCONNEXION_VENDOR, vrpn_3DCONNEXION_NAVIGATOR_FOR_NOTEBOOKS), 2, name, c)
320 {
321 }
322 
324  : vrpn_3DConnexion(_filter = new vrpn_HidProductAcceptor(vrpn_3DCONNEXION_VENDOR, vrpn_3DCONNEXION_TRAVELER), 8, name, c)
325 {
326 }
327 
329  : vrpn_3DConnexion(_filter = new vrpn_HidProductAcceptor(vrpn_3DCONNEXION_VENDOR, vrpn_3DCONNEXION_SPACEMOUSE), 11, name, c)
330 {
331 }
332 
334 : vrpn_3DConnexion(_filter = new vrpn_HidProductAcceptor(vrpn_3DCONNEXION_VENDOR, vrpn_3DCONNEXION_SPACEMOUSEPRO), 27, name, c)
335 { // 15 physical buttons are numbered: 0-2, 4-5, 8, 12-15, 22-26
336 }
337 
339  : vrpn_3DConnexion(_filter = new vrpn_HidProductAcceptor(vrpn_SPACEMOUSEWIRELESS_VENDOR, vrpn_3DCONNEXION_SPACEMOUSEWIRELESS), 2, name, c)
340 {
341 }
342 
344  : vrpn_3DConnexion(_filter = new vrpn_HidProductAcceptor(vrpn_3DCONNEXION_VENDOR, vrpn_3DCONNEXION_SPACEEXPLORER), 15, name, c)
345 {
346 }
347 
349  : vrpn_3DConnexion(_filter = new vrpn_HidProductAcceptor(vrpn_3DCONNEXION_VENDOR, vrpn_3DCONNEXION_SPACEBALL5000), 12, name, c)
350 {
351 }
352 
354  : vrpn_3DConnexion(_filter = new vrpn_HidProductAcceptor(vrpn_3DCONNEXION_VENDOR, vrpn_3DCONNEXION_SPACEPILOT), 21, name, c)
355 {
356 }
vrpn_3DConnexion.h
vrpn_3DConnexion::vrpn_3DConnexion
vrpn_3DConnexion(vrpn_HidAcceptor *filter, unsigned num_buttons, const char *name, vrpn_Connection *c=0)
Definition: vrpn_3DConnexion.C:37
vrpn_3DConnexion_SpacePilot::vrpn_3DConnexion_SpacePilot
vrpn_3DConnexion_SpacePilot(const char *name, vrpn_Connection *c=0)
Definition: vrpn_3DConnexion.C:353
vrpn_3DConnexion_SpaceMouse::vrpn_3DConnexion_SpaceMouse
vrpn_3DConnexion_SpaceMouse(const char *name, vrpn_Connection *c=0)
Definition: vrpn_3DConnexion.C:328
vrpn_Button::report_changes
virtual void report_changes(void)
Definition: vrpn_Button.C:422
vrpn_BaseClass.h
vrpn_HIDDEVINFO
Definition: vrpn_HumanInterface.h:39
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_HIDDEVINFO::product
vrpn_uint16 product
Definition: vrpn_HumanInterface.h:41
vrpn_noint_select
int vrpn_noint_select(int width, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
This routine will perform like a normal select() call, but it will restart if it quit because of an i...
Definition: vrpn_Connection.C:1615
vrpn_3DConnexion_SpaceExplorer::vrpn_3DConnexion_SpaceExplorer
vrpn_3DConnexion_SpaceExplorer(const char *name, vrpn_Connection *c=0)
Definition: vrpn_3DConnexion.C:343
vrpn_HidInterface
Definition: vrpn_HumanInterface.h:68
vrpn_3DConnexion::_timestamp
struct timeval _timestamp
Definition: vrpn_3DConnexion.h:41
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_Analog
Definition: vrpn_Analog.h:28
vrpn_Analog::timestamp
struct timeval timestamp
Definition: vrpn_Analog.h:41
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_HIDDEVINFO::vendor
vrpn_uint16 vendor
Definition: vrpn_HumanInterface.h:40
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_TEXT_ERROR
@ vrpn_TEXT_ERROR
Definition: vrpn_BaseClass.h:103
vrpn_HidProductAcceptor
Accepts any device with the given vendor and product IDs.
Definition: vrpn_HumanInterface.h:150
vrpn_TEXT_WARNING
@ vrpn_TEXT_WARNING
Definition: vrpn_BaseClass.h:102
vrpn_3DConnexion::decodePacket
virtual void decodePacket(size_t bytes, vrpn_uint8 *buffer)
Definition: vrpn_3DConnexion.C:211
vrpn_Button::timestamp
struct timeval timestamp
Definition: vrpn_Button.h:48
vrpn_3DConnexion::mainloop
virtual void mainloop()
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
Definition: vrpn_3DConnexion.C:118
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
EV_KEY
#define EV_KEY
Definition: vrpn_Event_Mouse.C:33
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_3DConnexion_SpaceBall5000::vrpn_3DConnexion_SpaceBall5000
vrpn_3DConnexion_SpaceBall5000(const char *name, vrpn_Connection *c=0)
Definition: vrpn_3DConnexion.C:348
vrpn_3DConnexion::report
void report(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY)
Definition: vrpn_3DConnexion.C:183
vrpn_3DConnexion_Navigator_for_Notebooks::vrpn_3DConnexion_Navigator_for_Notebooks
vrpn_3DConnexion_Navigator_for_Notebooks(const char *name, vrpn_Connection *c=0)
Definition: vrpn_3DConnexion.C:318
vrpn_Analog::last
vrpn_float64 last[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:39
vrpn_HidAcceptor::accept
virtual bool accept(const vrpn_HIDDEVINFO &device)=0
vrpn_3DConnexion::on_data_received
void on_data_received(size_t bytes, vrpn_uint8 *buffer)
Derived class reimplements this callback.
Definition: vrpn_3DConnexion.C:112
vrpn_3DConnexion_Navigator::vrpn_3DConnexion_Navigator
vrpn_3DConnexion_Navigator(const char *name, vrpn_Connection *c=0)
Definition: vrpn_3DConnexion.C:313
vrpn_noint_block_read
int vrpn_noint_block_read(int infile, char buffer[], size_t length)
Definition: vrpn_Connection.C:1757
vrpn_3DConnexion_SpaceMousePro::vrpn_3DConnexion_SpaceMousePro
vrpn_3DConnexion_SpaceMousePro(const char *name, vrpn_Connection *c=0)
Definition: vrpn_3DConnexion.C:333
vrpn_BaseClassUnique::send_text_message
int send_text_message(const char *msg, struct timeval timestamp, vrpn_TEXT_SEVERITY type=vrpn_TEXT_NORMAL, vrpn_uint32 level=0)
Sends a NULL-terminated text message from the device d_sender_id.
Definition: vrpn_BaseClass.C:568
vrpn_Connection::send_pending_reports
virtual int send_pending_reports(void)=0
send pending report, clear the buffer. This function was protected, now is public,...
vrpn_3DConnexion_SpaceMouseWireless::vrpn_3DConnexion_SpaceMouseWireless
vrpn_3DConnexion_SpaceMouseWireless(const char *name, vrpn_Connection *c=0)
Definition: vrpn_3DConnexion.C:338
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_3DConnexion::~vrpn_3DConnexion
virtual ~vrpn_3DConnexion()
Definition: vrpn_3DConnexion.C:103
vrpn_3DConnexion
Definition: vrpn_3DConnexion.h:28
vrpn_3DConnexion::_filter
vrpn_HidAcceptor * _filter
Definition: vrpn_3DConnexion.h:42
EV_REL
#define EV_REL
Definition: vrpn_Event_Mouse.C:34
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_3DConnexion_Traveler::vrpn_3DConnexion_Traveler
vrpn_3DConnexion_Traveler(const char *name, vrpn_Connection *c=0)
Definition: vrpn_3DConnexion.C:323
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