vrpn 07.35
Virtual Reality Peripheral Network
Loading...
Searching...
No Matches
vrpn_HumanInterface.C
Go to the documentation of this file.
1#include <stdio.h> // for fprintf, stderr
2
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
14vrpn_uint16 vrpn_HidInterface::vendor() const { return m_vendor; }
15
16// Accessor for USB product ID of connected device
17vrpn_uint16 vrpn_HidInterface::product() const { return m_product; }
18
19// Accessor for USB interface number of connected device
21
22// Returns true iff everything was working last time we checked
24
26 hid_device *device)
27 : m_acceptor(acceptor)
28 , m_working(false)
29 , m_vendor(0)
30 , m_product(0)
31 , m_interface(0)
32 , m_vendor_sought(0 /*vendor*/)
33 , m_product_sought(0 /*product*/)
34 , m_device(device)
35{
36 if (!m_acceptor) {
37 print_error("vrpn_HidInterface", "NULL acceptor", false);
38 return;
39 }
40 if (!m_device) {
43 reconnect();
44 return;
45 }
46 // We'll let this method set m_working for us, if it is, in fact, working.
47 finish_setup();
48}
49
51 vrpn_uint16 vendor, vrpn_uint16 product,
52 hid_device *device)
53 : m_acceptor(acceptor)
54 , m_working(false)
55 , m_vendor(0)
56 , m_product(0)
57 , m_interface(0)
58 , m_vendor_sought(vendor)
59 , m_product_sought(product)
60 , m_device(device)
61{
62 if (!m_acceptor) {
63 print_error("vrpn_HidInterface", "NULL acceptor", false);
64 return;
65 }
66 if (!m_device) {
69 reconnect();
70 return;
71 }
72 // We'll let this method set m_working for us, if it is, in fact, working.
73 finish_setup();
74}
75
77 vrpn_HidAcceptor *acceptor,
78 vrpn_uint16 vendor, vrpn_uint16 product)
79 : m_acceptor(acceptor)
80 , m_working(false)
81 , m_vendor(0)
82 , m_product(0)
83 , m_interface(0)
84 , m_vendor_sought(vendor)
85 , m_product_sought(product)
86 , m_device(NULL)
87{
88 if (!m_acceptor) {
89 print_error("vrpn_HidInterface", "NULL acceptor", false);
90 return;
91 }
92 if (!device_path || !(device_path[0])) {
95 reconnect();
96 return;
97 }
98
99 // Initialize the HID interface and open the device.
100 m_device = hid_open_path(device_path);
101 if (m_device == NULL) {
102 fprintf(stderr, "vrpn_HidInterface::vrpn_HidInterface(): Could not "
103 "open device %s\n",
104 device_path);
105#ifdef linux
106 fprintf(stderr, " (Did you remember to run as root or otherwise set "
107 "permissions?)\n");
108#endif
109 print_hidapi_error("vrpn_HidInterface");
110 }
111 // We'll let this method set m_working for us, if it is, in fact, working.
112 finish_setup();
113}
114
116{
117 if (m_device) {
118 hid_close(m_device);
119 m_device = NULL;
120 }
121}
122
123namespace {
125 class EnumerationFreer {
126 public:
127 typedef struct hid_device_info *EnumerationType;
128 explicit EnumerationFreer(EnumerationType &devs)
129 : devs_(devs)
130 {
131 }
132 ~EnumerationFreer()
133 {
134 hid_free_enumeration(devs_);
135 devs_ = NULL;
136 }
137
138 private:
139 EnumerationType &devs_;
140 };
141} // namespace
142
143// Reconnects the device I/O for the first acceptable device
144// Called automatically by constructor, but userland code can
145// use it to reacquire a hotplugged device.
147{
148 // Enumerate all devices and pass each one to the acceptor to see if it
149 // is the one that we want.
150 struct hid_device_info *devs =
151 hid_enumerate(m_vendor_sought, m_product_sought);
152 struct hid_device_info *loop = devs;
153
154 // This will free the enumeration when it goes out of scope: has to stick
155 // around until after the call to open. The serial number (path?) is a
156 // pointer to a
157 // string down in there.
158 EnumerationFreer freeEnumeration(devs);
159
160 bool found = false;
161 const wchar_t *serial;
162 const char *path;
163 while ((loop != NULL) && !found) {
164 vrpn_HIDDEVINFO device_info;
165 device_info.vendor = loop->vendor_id;
166 device_info.product = loop->product_id;
167 device_info.serial_number = loop->serial_number;
168 device_info.manufacturer_string = loop->manufacturer_string;
169 device_info.product_string = loop->product_string;
170 device_info.interface_number = loop->interface_number;
171 device_info.path = loop->path;
172 // printf("XXX Found vendor 0x%x, product 0x%x, interface %d\n",
173 // (unsigned)(loop->vendor_id), (unsigned)(loop->product_id),
174 // (int)(loop->interface_number) );
175
176 if (m_acceptor->accept(device_info)) {
177 m_vendor = loop->vendor_id;
178 m_product = loop->product_id;
179 m_interface = loop->interface_number;
180 serial = loop->serial_number;
181 path = loop->path;
182 found = true;
183#ifdef VRPN_HID_DEBUGGING
184 fprintf(stderr, "vrpn_HidInterface::reconnect(): Found %ls %ls "
185 "(%04hx:%04hx) at path %s - will attempt to "
186 "open.\n",
187 loop->manufacturer_string, loop->product_string, m_vendor,
188 m_product, loop->path);
189#endif
190 }
191 loop = loop->next;
192 }
193 if (!found) {
194 // fprintf(stderr, "vrpn_HidInterface::reconnect(): Device not
195 // found\n");
196 return false;
197 }
198
199 // Initialize the HID interface and open the device.
200 m_device = hid_open_path(path);
201 if (m_device == NULL) {
202 fprintf(stderr,
203 "vrpn_HidInterface::reconnect(): Could not open device %s\n",
204 path);
205#ifdef linux
206 fprintf(stderr, " (Did you remember to run as root or otherwise set "
207 "permissions?)\n");
208#endif
209 print_hidapi_error("reconnect");
210 return false;
211 }
212
213 return finish_setup();
214}
215
216bool vrpn_HidInterface::finish_setup()
217{
218 if (!m_device) {
219 m_working = false;
220 return false;
221 }
222 // Set the device to non-blocking mode.
223 if (hid_set_nonblocking(m_device, 1) != 0) {
224 print_error("finish_setup", "Could not set device to nonblocking");
225 return false;
226 }
227
228#ifdef VRPN_HID_DEBUGGING
229 fprintf(stderr,
230 "vrpn_HidInterface::reconnect(): Device successfully opened.\n");
231#endif
232 m_working = true;
233 return m_working;
234}
235
236// Check for incoming characters. If we get some, pass them on to the handler
237// code.
238
240{
241 if (!m_working) {
242 // fprintf(stderr,"vrpn_HidInterface::update(): Interface not currently
243 // working\n");
244 return;
245 }
246
247 // Maximum packet size for USB is 512 characters.
248 vrpn_uint8 inbuf[512];
249
250 // Continue reading until we eat up all of the reports. If we only handle
251 // one report per loop cycle, we can accumulate latency.
252 int ret;
253 do {
254 ret = hid_read(m_device, inbuf, sizeof(inbuf));
255 if (ret < 0) {
256 print_error("update", "Read error");
257 m_working = false;
258 return;
259 }
260
261 // Handle any data we got. This can include fewer bytes than we
262 // asked for.
263 if (ret > 0) {
264 vrpn_uint8 *data =
265 static_cast<vrpn_uint8 *>(static_cast<void *>(inbuf));
266 on_data_received(ret, data);
267 }
268 } while (ret > 0);
269}
270
271// This is based on sample code from UMinn Duluth at
272// http://www.d.umn.edu/~cprince/PubRes/Hardware/LinuxUSB/PICDEM/tutorial1.c
273// It has not yet been tested.
274
275void vrpn_HidInterface::send_data(size_t bytes, const vrpn_uint8 *buffer)
276{
277 if (!m_working) {
278 print_error("send_data", "Interface not currently working", false);
279 return;
280 }
281 int ret;
282 if ((ret = hid_write(m_device, const_cast<vrpn_uint8 *>(buffer), bytes)) !=
283 static_cast<int>(bytes)) {
284 print_error("send_data", "hid_write failed");
285 }
286}
287
289 const vrpn_uint8 *buffer)
290{
291 if (!m_working) {
292 print_error("get_feature_report", "Interface not currently working",
293 false);
294 return;
295 }
296
297 int ret = hid_send_feature_report(m_device, buffer, bytes);
298 if (ret == -1) {
299 print_error("send_feature_report", "failed to send feature report");
300 }
301 else {
302 // fprintf(stderr, "vrpn_HidInterface::send_feature_report(): sent
303 // feature report, %d bytes\n", static_cast<int>(bytes));
304 }
305}
306
307int vrpn_HidInterface::get_feature_report(size_t bytes, vrpn_uint8 *buffer)
308{
309 if (!m_working) {
310 print_error("get_feature_report", "Interface not currently working",
311 false);
312 return -1;
313 }
314
315 int ret = hid_get_feature_report(m_device, buffer, bytes);
316 if (ret == -1) {
317 print_error("get_feature_report", "failed to get feature report");
318 }
319 else {
320 // fprintf(stderr, "vrpn_HidInterface::get_feature_report(): got feature
321 // report, %d bytes\n", static_cast<int>(bytes));
322 }
323 return ret;
324}
325
326void vrpn_HidInterface::print_error(const char *function, const char *msg,
327 bool askHIDAPI) const
328{
329 fprintf(stderr, "vrpn_HidInterface::%s(): %s\n", function, msg);
330 if (!askHIDAPI || !m_device) {
331 return;
332 }
333 print_hidapi_error(function);
334}
335
336void vrpn_HidInterface::print_hidapi_error(const char *function) const
337{
338 const wchar_t *errmsg = hid_error(m_device);
339 if (!errmsg) {
340 return;
341 }
342 fprintf(stderr, "vrpn_HidInterface::%s(): error message: %ls\n", function,
343 errmsg);
344}
345
346#endif
virtual void reset()
virtual bool accept(const vrpn_HIDDEVINFO &device)=0
vrpn_uint16 product() const
Returns USB product ID of connected device May not contain valid if an already-open device was provid...
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 ...
virtual bool reconnect()
Tries to reconnect to an acceptable device. Call this if you suspect a hotplug event has occurred.
vrpn_uint16 m_product_sought
What product we want.
vrpn_HidInterface(vrpn_HidAcceptor *acceptor, vrpn_uint16 vendor=0, vrpn_uint16 product=0, hid_device *device=NULL)
Constructor If we already have a HID device from some other source, it can be passed and we'll take o...
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...
vrpn_HidAcceptor * m_acceptor
This is the HidAcceptor we use when reconnecting.
virtual void update()
Polls the device buffers and causes on_data_received callbacks if appropriate You NEED to call this f...
virtual bool connected() const
Returns true iff the last device I/O succeeded.
virtual void on_data_received(size_t bytes, vrpn_uint8 *buffer)=0
Derived class reimplements this callback.
vrpn_uint16 m_vendor_sought
What vendor we want.
vrpn_uint16 vendor() const
Returns USB vendor ID of connected device May not contain valid if an already-open device was provide...
void send_data(size_t bytes, const vrpn_uint8 *buffer)
Call this to send data to the device.
int interface_number() const
Returns the USB interface number of connected device May not contain valid information on all platfor...
wchar_t * manufacturer_string
struct hid_device_ hid_device