vrpn 07.35
Virtual Reality Peripheral Network
Loading...
Searching...
No Matches
vrpn_LUDL.C
Go to the documentation of this file.
1// Device drivers for the LUDL family of translation stage controllers.
2
3// XXX I think we're using ASCII send and response because Ryan had some kind of trouble
4// with the binary send/response. Not sure about this, though. It sure would be
5// faster to read and easier to parse the binary ones, which all have the same length.
6// XXX If we don't recenter, then we definitely need a way to figure out where
7// our analogs are.
8// XXX Need to parse more than one report if there is more than one in the buffer
9// Also, need to clear _inbuf after each parsing.
10// XXX Switch the reads (at least) to be asynchronous transfers.
11// XXX Consider querying/parsing the position rather than just the status.
12// XXX Make sure that we get notified if the user moves the stage with the knobs.
13// XXX Check for running into the limits.
14
15#include "vrpn_LUDL.h"
16
18
19#if defined(VRPN_USE_LIBUSB_1_0)
20
21#include <stdio.h> // for fprintf, stderr, sprintf, etc
22#include <string.h> // for NULL, memset, strlen
23
24#include "libusb.h"
25#include "vrpn_BaseClass.h" // for ::vrpn_TEXT_ERROR
26
27#define REPORT_ERROR(msg) { send_text_message(msg, timestamp, vrpn_TEXT_ERROR) ; if (d_connection && d_connection->connected()) d_connection->send_pending_reports(); }
28
29// USB vendor and product IDs for the models we support
30static const vrpn_uint16 LUDL_VENDOR = 0x6969;
31static const vrpn_uint16 LUDL_USBMAC6000 = 0x1235;
32
33// Constants used in the LUDL commands and responses.
34static const vrpn_uint16 LUDL_GET_LONG_DATA = 84;
35static const vrpn_uint16 LUDL_SET_LONG_DATA = 83;
36static const vrpn_uint16 LUDL_MOTOR_ACTION = 65;
37
38// Index constants used by the above commands and responses.
39static const vrpn_uint16 LUDL_MOTOR_POSITION = 5;
40static const vrpn_uint16 LUDL_MODULE_BUSY = 63;
41static const vrpn_uint16 LUDL_START_MOTOR_TARGET = 0;
42static const vrpn_uint16 LUDL_CENTER_HOME = 7;
43static const vrpn_uint16 SERVO_CHECKING = 241;
44
45// Device number for the interface we're connected to.
46static const vrpn_uint16 LUDL_INTERFACE_ADDRESS = 32;
47
48vrpn_LUDL_USBMAC6000::vrpn_LUDL_USBMAC6000(const char *name, vrpn_Connection *c, bool do_recenter)
49 : vrpn_Analog(name, c)
50 , vrpn_Analog_Output(name, c)
51 , _device_handle(NULL)
52 , _endpoint(2) // All communications is with Endpoint 2 for the MAC6000
53 , _incount(0)
54{
55 // Open and claim a device with the expected vendor and product ID.
56 if ( libusb_init(&_context) != 0) {
57 fprintf(stderr,"vrpn_LUDL_USBMAC6000: can't init LibUSB\n");
58 return;
59 }
60 //printf("dbg: Opening device\n");
61 if ( (_device_handle = libusb_open_device_with_vid_pid(_context, LUDL_VENDOR, LUDL_USBMAC6000)) == NULL) {
62 fprintf(stderr,"vrpn_LUDL_USBMAC6000: can't find any USBMac6000 devices\n");
63#ifdef _WIN32
64 fprintf(stderr," (Did you install a Zadig.exe or other LibUSB-compatible driver?)\n");
65#endif
66#ifdef linux
67 fprintf(stderr," (Did you remember to run as root?)\n");
68#endif
69 return;
70 }
71 //printf("dbg: Claiming interface\n");
72 if ( libusb_claim_interface(_device_handle, 0) != 0) {
73 fprintf(stderr,"vrpn_LUDL_USBMAC6000: can't claim interface for this device\n");
74#ifdef linux
75 fprintf(stderr," (Did you remember to run as root?)\n");
76#endif
77 libusb_close(_device_handle);
78 _device_handle = NULL;
79 libusb_exit(_context);
80 _context = NULL;
81 return;
82 }
83
84 // Initialize our analog values.
86 memset(channel, 0, sizeof(channel));
87 memset(last, 0, sizeof(last));
88
89 // Initialize our analog output values
91 memset(o_channel, 0, sizeof(o_channel));
92
93 // Recenter if we have been asked to. This takes a long time, during which the
94 // constructor is locked up.
95 if (do_recenter) {
96 //printf("dbg: Recentering\n");
97 recenter();
98 }
99
100 // Tell the X and Y channel to do servo checking, which means that it will
101 // cause the system to actively work to hold the system in place when it
102 // has reached its destination. This turns out to greatly improve the
103 // precision of motion, and make the precision uniform across particular
104 // locations. Before this was turned on, there was a positional dependence
105 // to the amount of error in moving the stage.
106 if (!send_usbmac_command(1, LUDL_SET_LONG_DATA, SERVO_CHECKING, 1)) {
107 REPORT_ERROR("vrpn_LUDL_USBMAC6000::vrpn_LUDL_USBMAC6000(): Could not send command 1");
108 }
109 if (!send_usbmac_command(2, LUDL_SET_LONG_DATA, SERVO_CHECKING, 1)) {
110 REPORT_ERROR("vrpn_LUDL_USBMAC6000::vrpn_LUDL_USBMAC6000(): Could not send command 2");
111 }
112
113 // Wait for these commands to take effect and then clear any return
114 // values
115 vrpn_SleepMsecs(100);
116 flush_input_from_ludl();
117
118 // Register to receive the message to request changes and to receive connection
119 // messages.
120 if (d_connection != NULL) {
122 this, d_sender_id)) {
123 fprintf(stderr,"vrpn_LUDL_USBMAC6000: can't register handler\n");
124 d_connection = NULL;
125 }
127 this, d_sender_id)) {
128 fprintf(stderr,"vrpn_LUDL_USBMAC6000: can't register handler\n");
129 d_connection = NULL;
130 }
132 this, d_sender_id)) {
133 fprintf(stderr,"vrpn_LUDL_USBMAC6000: can't register handler\n");
134 d_connection = NULL;
135 }
136 } else {
137 fprintf(stderr,"vrpn_LUDL_USBMAC6000: Can't get connection!\n");
138 }
139
140 // Allocate space to store the axis status and record that the axes are stopped.
141 _axis_moving = new bool[o_num_channel];
142 _axis_destination = new vrpn_float64[o_num_channel];
143 int i;
144 for (i = 0; i < o_num_channel; i++) {
145 _axis_moving[i] = false;
146 }
147}
148
150{
151 if (_device_handle) {
152 libusb_close(_device_handle);
153 _device_handle = NULL;
154 }
155 if (_context) {
156 libusb_exit(_context);
157 _context = NULL;
158 }
159
160 // Get rid of the arrays we allocated in the constructor
161 try {
162 if (_axis_moving != NULL) { delete[] _axis_moving; _axis_moving = NULL; }
163 if (_axis_destination != NULL) { delete[] _axis_destination; _axis_destination = NULL; }
164 } catch (...) {
165 fprintf(stderr, "vrpn_LUDL_USBMAC6000::~vrpn_LUDL_USBMAC6000(): delete failed\n");
166 return;
167 }
168
169}
170
172{
173 if (_device_handle == NULL) {
174 return false;
175 }
176
177 // Let libusb handle any outstanding events
178 struct timeval zerotime;
179 zerotime.tv_sec = 0;
180 zerotime.tv_usec = 0;
181 libusb_handle_events_timeout(_context, &zerotime);
182
183 // Try to read as many characters as are left in the buffer from
184 // the device. Keep track of how many we get.
185
186 int chars_to_read = _INBUFFER_SIZE - _incount;
187 int chars_read = 0;
188 int ret;
189 //printf("dbg: Starting bulk receive\n");
190 ret = libusb_bulk_transfer(_device_handle, _endpoint | LIBUSB_ENDPOINT_IN,
191 &_inbuffer[_incount], chars_to_read, &chars_read, 1);
192 //printf("dbg: Finished bulk receive\n");
193 if ( (ret != LIBUSB_SUCCESS) && (ret != LIBUSB_ERROR_TIMEOUT) ) {
194#ifdef libusb_strerror
195 fprintf(stderr, "vrpn_LUDL_USBMAC6000::check_for_data(): Could not read data: %s\n",
196 libusb_strerror(static_cast<libusb_error>(ret)));
197#else
198 fprintf(stderr, "vrpn_LUDL_USBMAC6000::check_for_data(): Could not read data: code %d\n",
199 ret);
200#endif
201
202 return false;
203 }
204 _incount += chars_read;
205 return true;
206}
207
208
210{
211 if (_device_handle == NULL) {
212 return;
213 }
214
215 // Let libusb handle any outstanding events
216 struct timeval zerotime;
217 zerotime.tv_sec = 0;
218 zerotime.tv_usec = 0;
219 libusb_handle_events_timeout(_context, &zerotime);
220
221 // If one of the axes is moving, check to see whether it has stopped.
222 // If so, report its new position.
223 // XXX Would like to change this to poll (or have the device send
224 // continuously) the actual position, rather than relying on it having
225 // gotten where we asked it to go).
226 if (!_axis_moving || !_axis_destination) { return; }
227 int i;
228 for (i = 0; i < o_num_channel; i++) {
229 if (_axis_moving[i]) {
230 if (!ludl_axis_moving(i+1)) {
231 vrpn_Analog::channel[i] = _axis_destination[i];
232 _axis_moving[i] = false;
233 }
234 }
235 }
236
237 // Ask for and record the positions of the two axes.
238 // Remember that the axes are numbered starting from 1 on the
239 // LUDL controller but they go in Analog channels 2 and 3.
240 vrpn_int32 position;
241 if (ludl_axis_position(1, &position)) {
242 channel[2] = position;
243 }
244 if (ludl_axis_position(2, &position)) {
245 channel[3] = position;
246 }
247
248 // Let all of the servers do their thing.
252
253 // Call the server_mainloop on our unique base class.
255}
256
257void vrpn_LUDL_USBMAC6000::report(vrpn_uint32 class_of_service)
258{
260 vrpn_Analog::report(class_of_service);
261}
262
263void vrpn_LUDL_USBMAC6000::report_changes(vrpn_uint32 class_of_service)
264{
266 vrpn_Analog::report_changes(class_of_service);
267}
268
269void vrpn_LUDL_USBMAC6000::flush_input_from_ludl(void)
270{
271 // Clear the input buffer, read all available characters
272 // from the endpoint we're supposed to use, then clear it
273 // again -- throwing away all data that was coming from the device.
274 _incount = 0;
276 _incount = 0;
277}
278
279// Construct a command using the specific language of the USBMAC6000
280// and send the message to the device.
281// I got the format for this message from the code in USBMAC6000.cpp from
282// the video project, as implemented by Ryan Schubert at UNC.
283bool vrpn_LUDL_USBMAC6000::send_usbmac_command(unsigned device, unsigned command, unsigned index, int value)
284{
285 if (_device_handle == NULL) {
286 return false;
287 }
288
289 // Let libusb handle any outstanding events
290 struct timeval zerotime;
291 zerotime.tv_sec = 0;
292 zerotime.tv_usec = 0;
293 libusb_handle_events_timeout(_context, &zerotime);
294
295 char msg[1024];
296 sprintf(msg, "can %u %u %u %i\n", device, command, index, value);
297 int len = strlen(msg);
298 int sent_len = 0;
299 msg[len-1] = 0xD;
300
301 //printf("dbg: Starting bulk send command\n");
302 int ret = libusb_bulk_transfer(_device_handle, _endpoint | LIBUSB_ENDPOINT_OUT,
303 static_cast<vrpn_uint8 *>(static_cast<void*>(msg)),
304 len, &sent_len, 50);
305 //printf("dbg: Finished bulk send command\n");
306 if ((ret != 0) || (sent_len != len)) {
307#ifdef libusb_strerror
308 fprintf(stderr,"vrpn_LUDL_USBMAC6000::send_usbmac_command(): Could not send: %s\n",
309 libusb_strerror(static_cast<libusb_error>(ret)));
310#else
311 fprintf(stderr,"vrpn_LUDL_USBMAC6000::send_usbmac_command(): Could not send: code %d\n",
312 ret);
313#endif
314 return false;
315 }
316 return true;
317}
318
319// Interpret one response from the device and place its resulting value
320// in the return parameter.
321// I got the format for this message from the code in USBMAC6000.cpp from
322// the video project, as implemented by Ryan Schubert at UNC.
324 int *device_return,
325 int *command_return,
326 int *index_return,
327 int *value_return)
328{
329 if (buffer == NULL) { return false; }
330 const char *charbuf = static_cast<const char *>(static_cast<const void *>(buffer));
331
332 char acolon[32], can[32];
333 int device = 0, command = 0, index = 0, value = 0;
334 if (sscanf(charbuf, "%s %s %i %i %i %i", acolon, can, &device, &command, &index, &value) <= 0) {
335 REPORT_ERROR("vrpn_LUDL_USBMAC6000::interpret_usbmac_ascii_response(): Could not parse response");
336 return false;
337 }
338
339 *device_return = device;
340 *command_return = command;
341 *index_return = index;
342 *value_return = value;
343 return true;
344}
345
346// I got the algorithm for recentering from the code in USBMAC6000.cpp from
347// the video project, as implemented by Ryan Schubert at UNC.
348// XXX This takes a LONG TIME to finish and relies on messages coming back;
349// consider making it asynchronous.
350bool vrpn_LUDL_USBMAC6000::recenter(void)
351{
352 // Send the command to make the X axis go to both ends of its
353 // range and then move into the center.
354 if (!send_usbmac_command(1, LUDL_MOTOR_ACTION, LUDL_CENTER_HOME, 100000)) {
355 REPORT_ERROR("vrpn_LUDL_USBMAC6000::recenter(): Could not send command 1");
356 return false;
357 }
358 printf("vrpn_LUDL_USBMAC6000::recenter(): Waiting for X-axis center\n");
359 vrpn_SleepMsecs(500); // XXX Why sleep?
360
361 // Let libusb handle any outstanding events
362 struct timeval zerotime;
363 zerotime.tv_sec = 0;
364 zerotime.tv_usec = 0;
365 libusb_handle_events_timeout(_context, &zerotime);
366
367 flush_input_from_ludl();
368
369 // First we need to wait for the axis to start moving, then we need
370 // to wait for it to stop moving. This is because sometimes the
371 // X axis (at least) claims to be not moving even though we just
372 // told it to and flushed the buffer
373 while(!ludl_axis_moving(1)) {
374 vrpn_SleepMsecs(10);
375 libusb_handle_events_timeout(_context, &zerotime);
376 }
377 while(ludl_axis_moving(1)) {
378 vrpn_SleepMsecs(10);
379 libusb_handle_events_timeout(_context, &zerotime);
380 }
381
382 // Send the command to record the value at the center of the X axis as
383 // 694576 ticks. This magic number comes from the dividing by two the
384 // range on the UNC Monoptes system between the stops set to keep the
385 // objective from running into the walls of the plate. XXX Replace this
386 // with a more meaningful constant, perhaps 0.
387 if (!send_usbmac_command(1, LUDL_SET_LONG_DATA, LUDL_MOTOR_POSITION, 694576)) {
388 REPORT_ERROR("vrpn_LUDL_USBMAC6000::recenter(): Could not send command 2");
389 return false;
390 }
391 channel[0] = 694576;
392
393 // Send the command to make the Y axis go to both ends of its
394 // range and then move into the center.
395 if (!send_usbmac_command(2, LUDL_MOTOR_ACTION, LUDL_CENTER_HOME, 100000)) {
396 REPORT_ERROR("vrpn_LUDL_USBMAC6000::recenter(): Could not send command 3");
397 return false;
398 }
399 printf("vrpn_LUDL_USBMAC6000::recenter(): Waiting for Y-axis center\n");
400 vrpn_SleepMsecs(500); // XXX Why sleep?
401
402 // Let libusb handle any outstanding events
403 libusb_handle_events_timeout(_context, &zerotime);
404
405 flush_input_from_ludl();
406
407 // First we need to wait for the axis to start moving, then we need
408 // to wait for it to stop moving. This is because sometimes the
409 // X axis (at least) claims to be not moving even though we just
410 // told it to and flushed the buffer
411 while(!ludl_axis_moving(2)) {
412 vrpn_SleepMsecs(10);
413 libusb_handle_events_timeout(_context, &zerotime);
414 }
415 while(ludl_axis_moving(2)) {
416 vrpn_SleepMsecs(10);
417 libusb_handle_events_timeout(_context, &zerotime);
418 }
419
420 // Send the command to record the value at the center of the Y axis as
421 // 1124201 ticks. This magic number comes from the dividing by two the
422 // range on the UNC Monoptes system between the stops set to keep the
423 // objective from running into the walls of the plate. XXX Replace this
424 // with a more meaningful constant, perhaps 0.
425 if (!send_usbmac_command(2, LUDL_SET_LONG_DATA, LUDL_MOTOR_POSITION, 1124201)) {
426 REPORT_ERROR("vrpn_LUDL_USBMAC6000::recenter(): Could not send command 4");
427 return false;
428 }
429 channel[1] = 1124201;
430
431 return true;
432}
433
434// I got the algorithm for checking if the axis is moving
435// from the code in USBMAC6000.cpp from
436// the video project, as implemented by Ryan Schubert at UNC.
437// The first axis is 1 in this function.
438bool vrpn_LUDL_USBMAC6000::ludl_axis_moving(unsigned axis)
439{
440 // Request the status of the axis. In particular, we look at the
441 // bits telling whether each axis is busy.
442 flush_input_from_ludl();
443 if (!send_usbmac_command(LUDL_INTERFACE_ADDRESS, LUDL_GET_LONG_DATA, LUDL_MODULE_BUSY, 0)) {
444 REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_moving(): Could not send command 1");
445 return false;
446 }
447
448 // Read from the device to find the status. We call the check_for_data() method
449 // to look for a response.
450 unsigned watchdog = 0;
451 while (_incount == 0) {
452 if (!check_for_data()) {
453 REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_moving(): Could not get report");
454 return false;
455 }
456
457 // If it has been too long, re-send the request to the stage.
458 // XXX We should not be losing characters... figure out what is causing us to
459 // have to resend.
460 if (++watchdog == 25) { // 25 ms (timeout is 1ms)
461 if (!send_usbmac_command(LUDL_INTERFACE_ADDRESS, LUDL_GET_LONG_DATA, LUDL_MODULE_BUSY, 0)) {
462 REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_moving(): Could not resend command 1");
463 return false;
464 }
465 watchdog = 0;
466 }
467 }
468 int status = 0;
469 int device, command, index;
470 if (!interpret_usbmac_ascii_response(_inbuffer, &device, &command, &index, &status)) {
471 REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_moving(): Could not parse report");
472 return false;
473 }
474 _incount = 0; // XXX Should parse more than one report if there is one.
475 int axisMaskBit = 0x0001 << axis;
476 return (status & axisMaskBit) != 0;
477}
478
479// The first axis is 1 in this function.
480bool vrpn_LUDL_USBMAC6000::ludl_axis_position(unsigned axis, vrpn_int32 *position_return)
481{
482 // Request the position of the axis.
483 flush_input_from_ludl();
484 if (!send_usbmac_command(axis, LUDL_GET_LONG_DATA, LUDL_MOTOR_POSITION, 0)) {
485 REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_position(): Could not send command 1");
486 return false;
487 }
488
489 // Read from the device to find the status. We call the check_for_data() method
490 // to look for a response.
491 unsigned watchdog = 0;
492 while (_incount == 0) {
493 if (!check_for_data()) {
494 REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_position(): Could not get report");
495 return false;
496 }
497
498 // If it has been too long, re-send the request to the stage.
499 // XXX We should not be losing characters... figure out what is causing us to
500 // have to resend.
501 if (++watchdog == 25) { // 25 ms (timeout is 1ms)
502 if (!send_usbmac_command(axis, LUDL_GET_LONG_DATA, LUDL_MOTOR_POSITION, 0)) {
503 REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_position(): Could not resend command 1");
504 return false;
505 }
506 watchdog = 0;
507 }
508 }
509 int position = 0;
510 int device, command, index;
511 if (!interpret_usbmac_ascii_response(_inbuffer, &device, &command, &index, &position)) {
512 REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_position(): Could not parse report");
513 return false;
514 }
515 _incount = 0; // XXX Should parse more than one report if there is one.
516 if ( (command != LUDL_GET_LONG_DATA) || (index != LUDL_MOTOR_POSITION) ) {
517 REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_position(): Bad command or index in report");
518 return false;
519 }
520 *position_return = position;
521 return true;
522}
523
524bool vrpn_LUDL_USBMAC6000::move_axis_to_position(int axis, int position)
525{
526 if (!_device_handle) { return false; }
527 if (!_axis_destination || !_axis_moving) { return false; }
528
529 // If we're already at the place we're being asked to move to,
530 // then we just go ahead and return. Otherwise, the code below
531 // that waits for us to start moving hangs.
532 if (_axis_destination[axis-1] == position) {
533 return true;
534 }
535
536 // Send the command to the device asking it to move.
537 if (!send_usbmac_command(axis, LUDL_MOTOR_ACTION, LUDL_START_MOTOR_TARGET, position)) {
538 REPORT_ERROR("vrpn_LUDL_USBMAC6000::move_axis_to_position(): Could not send command");
539 return false;
540 }
541
542 // Wait until that axis starts to move. If we don't do this, then
543 // sometimes we hear back that there are no axes moving even though
544 // we told them to. Just waiting a while after we told them to move
545 // does not help; there is still a report saying that they are not moving.
546 // If the stage is at its limits or if we asked it to go where it already
547 // is, then we'll wait forever here because it will not move. So this
548 // needs to time out and not set the axis to moving if we never see
549 // it start to move.
550 struct timeval start, now;
551 vrpn_gettimeofday(&start, NULL);
552 while (!ludl_axis_moving(axis)) {
553 vrpn_gettimeofday(&now, NULL);
554 struct timeval diff = vrpn_TimevalDiff(now, start);
555 if (diff.tv_sec > 1) {
556 // Say that we moved there, but don't say that the axis is
557 // moving.
558 _axis_destination[axis-1] = position;
559 return true;
560 }
561 };
562
563 // Indicate that we're expecting this axis to be moving and where we think it is
564 // going, so that when the axis becomes no longer busy we know that we have gotten
565 // there.
566
567 _axis_destination[axis-1] = position;
568 _axis_moving[axis-1] = true;
569 return true;
570}
571
573{
574 const char *bufptr = p.buffer;
575 vrpn_int32 chan_num;
576 vrpn_int32 pad;
577 vrpn_float64 value;
579
580 // Read the parameters from the buffer
581 vrpn_unbuffer(&bufptr, &chan_num);
582 vrpn_unbuffer(&bufptr, &pad);
583 vrpn_unbuffer(&bufptr, &value);
584
585 // Set the position to the appropriate value, if the channel number is in the
586 // range of the ones we have.
587 if ( (chan_num < 0) || (chan_num >= me->o_num_channel) ) {
588 char msg[1024];
589 sprintf(msg,"vrpn_LUDL_USBMAC6000::handle_request_message(): Index out of bounds (%d of %d), value %lg\n",
590 chan_num, me->o_num_channel, value);
592 return 0;
593 }
594
595 me->move_axis_to_position(chan_num + 1, static_cast<int>(value));
596 return 0;
597}
598
600{
601 int i;
602 const char* bufptr = p.buffer;
603 vrpn_int32 num;
604 vrpn_int32 pad;
606
607 // Read the values from the buffer
608 vrpn_unbuffer(&bufptr, &num);
609 vrpn_unbuffer(&bufptr, &pad);
610 if (num > me->o_num_channel) {
611 char msg[1024];
612 sprintf(msg,"vrpn_LUDL_USBMAC6000::handle_request_channels_message(): Index out of bounds (%d of %d), clipping\n",
613 num, me->o_num_channel);
615 num = me->o_num_channel;
616 }
617 for (i = 0; i < num; i++) {
618 vrpn_unbuffer(&bufptr, &(me->o_channel[i]));
619 me->move_axis_to_position(i + 1, static_cast<int>(me->o_channel[i]));
620 }
621
622 return 0;
623}
624
628{
630
632 return 0;
633}
634
635// End of VRPN_USE_HID
636#endif
vrpn_float64 o_channel[vrpn_CHANNEL_MAX]
vrpn_int32 request_channels_m_id
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.
vrpn_int32 d_sender_id
Sender ID registered with the connection.
void server_mainloop(void)
Handles functions that all servers should provide in their mainloop() (ping/pong, for example) Should...
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.
vrpn_int32 d_ping_message_id
Ask the server if they are there.
Generic connection class not specific to the transport mechanism.
vrpn_uint8 _inbuffer[_INBUFFER_SIZE]
Definition: vrpn_LUDL.h:58
void report_changes(vrpn_uint32 class_of_service=vrpn_CONNECTION_RELIABLE)
Definition: vrpn_LUDL.C:263
bool interpret_usbmac_ascii_response(const vrpn_uint8 *buffer, int *device_return, int *command_return, int *index_return, int *value_return)
Definition: vrpn_LUDL.C:323
unsigned _endpoint
Definition: vrpn_LUDL.h:52
static int VRPN_CALLBACK handle_connect_message(void *userdata, vrpn_HANDLERPARAM p)
Responds to a connection request with a report of the values.
Definition: vrpn_LUDL.C:627
static int VRPN_CALLBACK handle_request_message(void *userdata, vrpn_HANDLERPARAM p)
Responds to a request to change one of the values by setting the channel to that value.
Definition: vrpn_LUDL.C:572
virtual void mainloop()
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
Definition: vrpn_LUDL.C:209
void report(vrpn_uint32 class_of_service=vrpn_CONNECTION_RELIABLE)
Definition: vrpn_LUDL.C:257
struct libusb_device_handle * _device_handle
Definition: vrpn_LUDL.h:50
struct timeval _timestamp
Definition: vrpn_LUDL.h:51
vrpn_LUDL_USBMAC6000(const char *name, vrpn_Connection *c=0, bool do_recenter=false)
Definition: vrpn_LUDL.C:48
virtual ~vrpn_LUDL_USBMAC6000()
Definition: vrpn_LUDL.C:149
struct libusb_context * _context
Definition: vrpn_LUDL.h:49
static int VRPN_CALLBACK handle_request_channels_message(void *userdata, vrpn_HANDLERPARAM p)
Responds to a request to change multiple channels at once.
Definition: vrpn_LUDL.C:599
static const unsigned _INBUFFER_SIZE
Definition: vrpn_LUDL.h:57
This structure is what is passed to a vrpn_Connection message callback.
const char * buffer
All types of client/server/peer objects in VRPN should be derived from the vrpn_BaseClass type descri...
@ vrpn_TEXT_ERROR
#define VRPN_SUPPRESS_EMPTY_OBJECT_WARNING()
const vrpn_uint32 vrpn_CONNECTION_RELIABLE
Classes of service for messages, specify multiple by ORing them together Priority of satisfying these...
#define REPORT_ERROR(msg)
Definition: vrpn_LUDL.C:27
VRPN_API int vrpn_unbuffer(const char **buffer, timeval *t)
Utility routine for taking a struct timeval from a buffer that was sent as a message.
Definition: vrpn_Shared.C:321
timeval vrpn_TimevalDiff(const timeval &tv1, const timeval &tv2)
Definition: vrpn_Shared.C:101
void vrpn_SleepMsecs(double dMilliSecs)
Definition: vrpn_Shared.C:166
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:99