vrpn  07.33
Virtual Reality Peripheral Network
vrpn_HumanInterface.C
Go to the documentation of this file.
1 #include <stdio.h> // for fprintf, stderr
2 
3 #include "vrpn_HumanInterface.h"
4 
5 #if defined(VRPN_USE_HID)
6 
7 #ifdef VRPN_USE_LOCAL_HIDAPI
8 #include "./submodules/hidapi/hidapi/hidapi.h" // for hid_device
9 #else
10 #include "hidapi.h"
11 #endif
12 
13 // Accessor for USB vendor ID of connected device
14 vrpn_uint16 vrpn_HidInterface::vendor() const { return _vendor; }
15 
16 // Accessor for USB product ID of connected device
17 vrpn_uint16 vrpn_HidInterface::product() const { return _product; }
18 
19 // Accessor for USB interface number of connected device
21 
22 // Returns true iff everything was working last time we checked
23 bool vrpn_HidInterface::connected() const { return _working; }
24 
26  : _acceptor(acceptor)
27  , _device(NULL)
28  , _working(false)
29  , _vendor(0)
30  , _product(0)
31  , _interface(0)
32 {
33  if (_acceptor == NULL) {
34  fprintf(stderr,
35  "vrpn_HidInterface::vrpn_HidInterface(): NULL acceptor\n");
36  return;
37  }
38 
39  // Reset the acceptor and then attempt to connect to a device.
40  _acceptor->reset();
41  reconnect();
42 }
43 
45 {
46  if (_device) {
47  hid_close(_device);
48  _device = NULL;
49  }
50 }
51 
52 // Reconnects the device I/O for the first acceptable device
53 // Called automatically by constructor, but userland code can
54 // use it to reacquire a hotplugged device.
56 {
57  // Enumerate all devices and pass each one to the acceptor to see if it
58  // is the one that we want.
59  struct hid_device_info *devs = hid_enumerate(0, 0);
60  struct hid_device_info *loop = devs;
61  bool found = false;
62  const wchar_t *serial;
63  const char *path;
64  while ((loop != NULL) && !found) {
65  vrpn_HIDDEVINFO device_info;
66  device_info.vendor = loop->vendor_id;
67  device_info.product = loop->product_id;
68  device_info.serial_number = loop->serial_number;
69  device_info.manufacturer_string = loop->manufacturer_string;
70  device_info.product_string = loop->product_string;
71  device_info.interface_number = loop->interface_number;
72  // printf("XXX Found vendor 0x%x, product 0x%x, interface %d\n",
73  // (unsigned)(loop->vendor_id), (unsigned)(loop->product_id),
74  // (int)(loop->interface_number) );
75 
76  if (_acceptor->accept(device_info)) {
77  _vendor = loop->vendor_id;
78  _product = loop->product_id;
79  _interface = loop->interface_number;
80  serial = loop->serial_number;
81  path = loop->path;
82  found = true;
83 #ifdef VRPN_HID_DEBUGGING
84  fprintf(stderr, "vrpn_HidInterface::reconnect(): Found %ls %ls "
85  "(%04hx:%04hx) at path %s - will attempt to "
86  "open.\n",
87  loop->manufacturer_string, loop->product_string, _vendor,
88  _product, loop->path);
89 #endif
90  }
91  loop = loop->next;
92  }
93  if (!found) {
94  fprintf(stderr, "vrpn_HidInterface::reconnect(): Device not found\n");
95  hid_free_enumeration(devs);
96  devs = NULL;
97  return false;
98  }
99 
100  // Initialize the HID interface and open the device.
101  _device = hid_open_path(path);
102  if (_device == NULL) {
103  fprintf(stderr,
104  "vrpn_HidInterface::reconnect(): Could not open device %s\n",
105  path);
106 #ifdef linux
107  fprintf(stderr, " (Did you remember to run as root?)\n");
108 #endif
109  hid_free_enumeration(devs);
110  devs = NULL;
111  return false;
112  }
113 
114  // We cannot do this before the call to open because the serial number
115  // is a pointer to a string down in there, which forms a race condition.
116  // This will be a memory leak if the device fails to open.
117  if (devs != NULL) {
118  hid_free_enumeration(devs);
119  devs = NULL;
120  }
121 
122  // Set the device to non-blocking mode.
123  if (hid_set_nonblocking(_device, 1) != 0) {
124  fprintf(stderr, "vrpn_HidInterface::reconnect(): Could not set device "
125  "to nonblocking\n");
126  return false;
127  }
128 
129 #ifdef VRPN_HID_DEBUGGING
130  fprintf(stderr,
131  "vrpn_HidInterface::reconnect(): Device successfully opened.\n");
132 #endif
133  _working = true;
134  return _working;
135 }
136 
137 // Check for incoming characters. If we get some, pass them on to the handler
138 // code.
139 
141 {
142  if (!_working) {
143  // fprintf(stderr,"vrpn_HidInterface::update(): Interface not currently
144  // working\n");
145  return;
146  }
147 
148  // Maximum packet size for USB is 512 characters.
149  vrpn_uint8 inbuf[512];
150 
151  // Continue reading until we eat up all of the reports. If we only handle
152  // one report per loop cycle, we can accumulate latency.
153  int ret;
154  do {
155  ret = hid_read(_device, inbuf, sizeof(inbuf));
156  if (ret < 0) {
157  fprintf(stderr, "vrpn_HidInterface::update(): Read error\n");
158 #if !defined(_WIN32) && !defined(__APPLE__)
159  fprintf(stderr, " (On one version of Red Hat Linux, this was from "
160  "not having libusb-devel installed when "
161  "configuring in CMake.)\n");
162 #endif
163  const wchar_t *errmsg = hid_error(_device);
164  if (errmsg) {
165  fprintf(
166  stderr,
167  "vrpn_HidInterface::update(): error message: %ls\n",
168  errmsg);
169  }
170  return;
171  }
172 
173  // Handle any data we got. This can include fewer bytes than we
174  // asked for.
175  if (ret > 0) {
176  vrpn_uint8 *data =
177  static_cast<vrpn_uint8 *>(static_cast<void *>(inbuf));
178  on_data_received(ret, data);
179  }
180  } while (ret > 0);
181 }
182 
183 // This is based on sample code from UMinn Duluth at
184 // http://www.d.umn.edu/~cprince/PubRes/Hardware/LinuxUSB/PICDEM/tutorial1.c
185 // It has not yet been tested.
186 
187 void vrpn_HidInterface::send_data(size_t bytes, const vrpn_uint8 *buffer)
188 {
189  if (!_working) {
190  fprintf(stderr, "vrpn_HidInterface::send_data(): Interface not "
191  "currently working\n");
192  return;
193  }
194  int ret;
195  if ((ret = hid_write(_device, const_cast<vrpn_uint8 *>(buffer), bytes)) !=
196  bytes) {
197  fprintf(stderr, "vrpn_HidInterface::send_data(): hid_interrupt_write() "
198  "failed with code %d\n",
199  ret);
200  }
201 }
202 
204  const vrpn_uint8 *buffer)
205 {
206  if (!_working) {
207  fprintf(stderr, "vrpn_HidInterface::send_feature_report(): Interface "
208  "not currently working\n");
209  return;
210  }
211 
212  int ret = hid_send_feature_report(_device, buffer, bytes);
213  if (ret == -1) {
214  fprintf(stderr, "vrpn_HidInterface::send_feature_report(): failed to "
215  "send feature report\n");
216  const wchar_t *errmsg = hid_error(_device);
217  if (errmsg) {
218  fprintf(stderr, "vrpn_HidInterface::send_feature_report(): error "
219  "message: %ls\n",
220  errmsg);
221  }
222  }
223  else {
224  // fprintf(stderr, "vrpn_HidInterface::send_feature_report(): sent
225  // feature report, %d bytes\n", static_cast<int>(bytes));
226  }
227 }
228 
229 int vrpn_HidInterface::get_feature_report(size_t bytes, vrpn_uint8 *buffer)
230 {
231  if (!_working) {
232  fprintf(stderr, "vrpn_HidInterface::get_feature_report(): Interface "
233  "not currently working\n");
234  return -1;
235  }
236 
237  int ret = hid_get_feature_report(_device, buffer, bytes);
238  if (ret == -1) {
239  fprintf(stderr, "vrpn_HidInterface::get_feature_report(): failed to "
240  "get feature report\n");
241  const wchar_t *errmsg = hid_error(_device);
242  if (errmsg) {
243  fprintf(
244  stderr,
245  "vrpn_HidInterface::get_feature_report(): error message: %ls\n",
246  errmsg);
247  }
248  }
249  else {
250  // fprintf(stderr, "vrpn_HidInterface::get_feature_report(): got feature
251  // report, %d bytes\n", static_cast<int>(bytes));
252  }
253  return ret;
254 }
255 
256 #endif // any interface
vrpn_HidInterface::~vrpn_HidInterface
virtual ~vrpn_HidInterface()
Definition: vrpn_HumanInterface.C:44
vrpn_HidInterface::connected
virtual bool connected() const
Returns true iff the last device I/O succeeded.
Definition: vrpn_HumanInterface.C:23
vrpn_HIDDEVINFO::product_string
wchar_t * product_string
Definition: vrpn_HumanInterface.h:44
vrpn_HIDDEVINFO
Definition: vrpn_HumanInterface.h:39
vrpn_HidInterface::send_feature_report
void send_feature_report(size_t bytes, const vrpn_uint8 *buffer)
Call this to send a feature report to the device - first byte must be Report ID (or 0x0 for devices w...
Definition: vrpn_HumanInterface.C:203
vrpn_HidInterface::reconnect
virtual bool reconnect()
Tries to reconnect to an acceptable device. Call this if you suspect a hotplug event has occurred.
Definition: vrpn_HumanInterface.C:55
vrpn_HidInterface::_interface
int _interface
Definition: vrpn_HumanInterface.h:132
vrpn_HIDDEVINFO::product
vrpn_uint16 product
Definition: vrpn_HumanInterface.h:41
vrpn_HidInterface::_vendor
vrpn_uint16 _vendor
Definition: vrpn_HumanInterface.h:130
vrpn_HidInterface::_product
vrpn_uint16 _product
Definition: vrpn_HumanInterface.h:131
vrpn_HidInterface::get_feature_report
int get_feature_report(size_t bytes, vrpn_uint8 *buffer)
Call this to get a feature report from the device - first byte must be Report ID (or 0x0 for devices ...
Definition: vrpn_HumanInterface.C:229
vrpn_HidInterface::interface_number
int interface_number() const
Returns the USB interface number of connected device.
Definition: vrpn_HumanInterface.C:20
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_HIDDEVINFO::vendor
vrpn_uint16 vendor
Definition: vrpn_HumanInterface.h:40
vrpn_HidInterface::product
vrpn_uint16 product() const
Returns USB product ID of connected device.
Definition: vrpn_HumanInterface.C:17
vrpn_HIDDEVINFO::interface_number
int interface_number
Definition: vrpn_HumanInterface.h:45
vrpn_HidInterface::_working
bool _working
Definition: vrpn_HumanInterface.h:129
vrpn_HidAcceptor::reset
virtual void reset()
Definition: vrpn_HumanInterface.h:58
vrpn_HumanInterface.h
vrpn_HidInterface::on_data_received
virtual void on_data_received(size_t bytes, vrpn_uint8 *buffer)=0
Derived class reimplements this callback.
vrpn_HidInterface::vendor
vrpn_uint16 vendor() const
Returns USB vendor ID of connected device.
Definition: vrpn_HumanInterface.C:14
vrpn_HidAcceptor::accept
virtual bool accept(const vrpn_HIDDEVINFO &device)=0
vrpn_HidInterface::vrpn_HidInterface
vrpn_HidInterface(vrpn_HidAcceptor *acceptor)
Definition: vrpn_HumanInterface.C:25
vrpn_HIDDEVINFO::serial_number
wchar_t * serial_number
Definition: vrpn_HumanInterface.h:42
vrpn_HidInterface::_acceptor
vrpn_HidAcceptor * _acceptor
This is the HidAcceptor we use when reconnecting.
Definition: vrpn_HumanInterface.h:127
vrpn_HidInterface::send_data
void send_data(size_t bytes, const vrpn_uint8 *buffer)
Call this to send data to the device.
Definition: vrpn_HumanInterface.C:187
vrpn_HIDDEVINFO::manufacturer_string
wchar_t * manufacturer_string
Definition: vrpn_HumanInterface.h:43