vrpn  07.33
Virtual Reality Peripheral Network
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
30 static const vrpn_uint16 LUDL_VENDOR = 0x6969;
31 static const vrpn_uint16 LUDL_USBMAC6000 = 0x1235;
32 
33 // Constants used in the LUDL commands and responses.
34 static const vrpn_uint16 LUDL_GET_LONG_DATA = 84;
35 static const vrpn_uint16 LUDL_SET_LONG_DATA = 83;
36 static const vrpn_uint16 LUDL_MOTOR_ACTION = 65;
37 
38 // Index constants used by the above commands and responses.
39 static const vrpn_uint16 LUDL_MOTOR_POSITION = 5;
40 static const vrpn_uint16 LUDL_MODULE_BUSY = 63;
41 static const vrpn_uint16 LUDL_START_MOTOR_TARGET = 0;
42 static const vrpn_uint16 LUDL_CENTER_HOME = 7;
43 static const vrpn_uint16 SERVO_CHECKING = 241;
44 
45 // Device number for the interface we're connected to.
46 static const vrpn_uint16 LUDL_INTERFACE_ADDRESS = 32;
47 
48 vrpn_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  , _incount(0)
53  , _endpoint(2) // All communications is with Endpoint 2 for the MAC6000
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  if ( (_axis_moving = new bool[o_num_channel]) == NULL) {
142  fprintf(stderr,"vrpn_LUDL_USBMAC6000: Out of memory\n");
143  }
144  if ( (_axis_destination = new vrpn_float64[o_num_channel]) == NULL) {
145  fprintf(stderr,"vrpn_LUDL_USBMAC6000: Out of memory\n");
146  }
147  int i;
148  for (i = 0; i < o_num_channel; i++) {
149  _axis_moving[i] = false;
150  }
151 }
152 
154 {
155  if (_device_handle) {
156  libusb_close(_device_handle);
157  _device_handle = NULL;
158  }
159  if (_context) {
160  libusb_exit(_context);
161  _context = NULL;
162  }
163 
164  // Get rid of the arrays we allocated in the constructor
165  if (_axis_moving != NULL) { delete [] _axis_moving; _axis_moving = NULL; }
166  if (_axis_destination != NULL) { delete [] _axis_destination; _axis_destination = NULL; }
167 }
168 
170 {
171  if (_device_handle == NULL) {
172  return false;
173  }
174 
175  // Let libusb handle any outstanding events
176  struct timeval zerotime;
177  zerotime.tv_sec = 0;
178  zerotime.tv_usec = 0;
179  libusb_handle_events_timeout(_context, &zerotime);
180 
181  // Try to read as many characters as are left in the buffer from
182  // the device. Keep track of how many we get.
183 
184  int chars_to_read = _INBUFFER_SIZE - _incount;
185  int chars_read = 0;
186  int ret;
187  //printf("dbg: Starting bulk receive\n");
188  ret = libusb_bulk_transfer(_device_handle, _endpoint | LIBUSB_ENDPOINT_IN,
189  &_inbuffer[_incount], chars_to_read, &chars_read, 1);
190  //printf("dbg: Finished bulk receive\n");
191  if ( (ret != LIBUSB_SUCCESS) && (ret != LIBUSB_ERROR_TIMEOUT) ) {
192 #ifdef libusb_strerror
193  fprintf(stderr, "vrpn_LUDL_USBMAC6000::check_for_data(): Could not read data: %s\n",
194  libusb_strerror(static_cast<libusb_error>(ret)));
195 #else
196  fprintf(stderr, "vrpn_LUDL_USBMAC6000::check_for_data(): Could not read data: code %d\n",
197  ret);
198 #endif
199 
200  return false;
201  }
202  _incount += chars_read;
203  return true;
204 }
205 
206 
208 {
209  if (_device_handle == NULL) {
210  return;
211  }
212 
213  // Let libusb handle any outstanding events
214  struct timeval zerotime;
215  zerotime.tv_sec = 0;
216  zerotime.tv_usec = 0;
217  libusb_handle_events_timeout(_context, &zerotime);
218 
219  // If one of the axes is moving, check to see whether it has stopped.
220  // If so, report its new position.
221  // XXX Would like to change this to poll (or have the device send
222  // continuously) the actual position, rather than relying on it having
223  // gotten where we asked it to go).
224  if (!_axis_moving || !_axis_destination) { return; }
225  int i;
226  for (i = 0; i < o_num_channel; i++) {
227  if (_axis_moving[i]) {
228  if (!ludl_axis_moving(i+1)) {
229  vrpn_Analog::channel[i] = _axis_destination[i];
230  _axis_moving[i] = false;
231  }
232  }
233  }
234 
235  // Ask for and record the positions of the two axes.
236  // Remember that the axes are numbered starting from 1 on the
237  // LUDL controller but they go in Analog channels 2 and 3.
238  vrpn_int32 position;
239  if (ludl_axis_position(1, &position)) {
240  channel[2] = position;
241  }
242  if (ludl_axis_position(2, &position)) {
243  channel[3] = position;
244  }
245 
246  // Let all of the servers do their thing.
247  server_mainloop();
249  report_changes();
250 
253 }
254 
255 void vrpn_LUDL_USBMAC6000::report(vrpn_uint32 class_of_service)
256 {
258  vrpn_Analog::report(class_of_service);
259 }
260 
261 void vrpn_LUDL_USBMAC6000::report_changes(vrpn_uint32 class_of_service)
262 {
264  vrpn_Analog::report_changes(class_of_service);
265 }
266 
267 void vrpn_LUDL_USBMAC6000::flush_input_from_ludl(void)
268 {
269  // Clear the input buffer, read all available characters
270  // from the endpoint we're supposed to use, then clear it
271  // again -- throwing away all data that was coming from the device.
272  _incount = 0;
273  check_for_data();
274  _incount = 0;
275 }
276 
277 // Construct a command using the specific language of the USBMAC6000
278 // and send the message to the device.
279 // I got the format for this message from the code in USBMAC6000.cpp from
280 // the video project, as implemented by Ryan Schubert at UNC.
281 bool vrpn_LUDL_USBMAC6000::send_usbmac_command(unsigned device, unsigned command, unsigned index, int value)
282 {
283  if (_device_handle == NULL) {
284  return false;
285  }
286 
287  // Let libusb handle any outstanding events
288  struct timeval zerotime;
289  zerotime.tv_sec = 0;
290  zerotime.tv_usec = 0;
291  libusb_handle_events_timeout(_context, &zerotime);
292 
293  char msg[1024];
294  sprintf(msg, "can %u %u %u %i\n", device, command, index, value);
295  int len = strlen(msg);
296  int sent_len = 0;
297  msg[len-1] = 0xD;
298 
299  //printf("dbg: Starting bulk send command\n");
300  int ret = libusb_bulk_transfer(_device_handle, _endpoint | LIBUSB_ENDPOINT_OUT,
301  static_cast<vrpn_uint8 *>(static_cast<void*>(msg)),
302  len, &sent_len, 50);
303  //printf("dbg: Finished bulk send command\n");
304  if ((ret != 0) || (sent_len != len)) {
305 #ifdef libusb_strerror
306  fprintf(stderr,"vrpn_LUDL_USBMAC6000::send_usbmac_command(): Could not send: %s\n",
307  libusb_strerror(static_cast<libusb_error>(ret)));
308 #else
309  fprintf(stderr,"vrpn_LUDL_USBMAC6000::send_usbmac_command(): Could not send: code %d\n",
310  ret);
311 #endif
312  return false;
313  }
314  return true;
315 }
316 
317 // Interpret one response from the device and place its resulting value
318 // in the return parameter.
319 // I got the format for this message from the code in USBMAC6000.cpp from
320 // the video project, as implemented by Ryan Schubert at UNC.
322  int *device_return,
323  int *command_return,
324  int *index_return,
325  int *value_return)
326 {
327  if (buffer == NULL) { return false; }
328  const char *charbuf = static_cast<const char *>(static_cast<const void *>(buffer));
329 
330  char acolon[32], can[32];
331  int device = 0, command = 0, index = 0, value = 0;
332  if (sscanf(charbuf, "%s %s %i %i %i %i", acolon, can, &device, &command, &index, &value) <= 0) {
333  REPORT_ERROR("vrpn_LUDL_USBMAC6000::interpret_usbmac_ascii_response(): Could not parse response");
334  return false;
335  }
336 
337  *device_return = device;
338  *command_return = command;
339  *index_return = index;
340  *value_return = value;
341  return true;
342 }
343 
344 // I got the algorithm for recentering from the code in USBMAC6000.cpp from
345 // the video project, as implemented by Ryan Schubert at UNC.
346 // XXX This takes a LONG TIME to finish and relies on messages coming back;
347 // consider making it asynchronous.
348 bool vrpn_LUDL_USBMAC6000::recenter(void)
349 {
350  // Send the command to make the X axis go to both ends of its
351  // range and then move into the center.
352  if (!send_usbmac_command(1, LUDL_MOTOR_ACTION, LUDL_CENTER_HOME, 100000)) {
353  REPORT_ERROR("vrpn_LUDL_USBMAC6000::recenter(): Could not send command 1");
354  return false;
355  }
356  printf("vrpn_LUDL_USBMAC6000::recenter(): Waiting for X-axis center\n");
357  vrpn_SleepMsecs(500); // XXX Why sleep?
358 
359  // Let libusb handle any outstanding events
360  struct timeval zerotime;
361  zerotime.tv_sec = 0;
362  zerotime.tv_usec = 0;
363  libusb_handle_events_timeout(_context, &zerotime);
364 
365  flush_input_from_ludl();
366 
367  // First we need to wait for the axis to start moving, then we need
368  // to wait for it to stop moving. This is because sometimes the
369  // X axis (at least) claims to be not moving even though we just
370  // told it to and flushed the buffer
371  while(!ludl_axis_moving(1)) {
372  vrpn_SleepMsecs(10);
373  libusb_handle_events_timeout(_context, &zerotime);
374  }
375  while(ludl_axis_moving(1)) {
376  vrpn_SleepMsecs(10);
377  libusb_handle_events_timeout(_context, &zerotime);
378  }
379 
380  // Send the command to record the value at the center of the X axis as
381  // 694576 ticks. This magic number comes from the dividing by two the
382  // range on the UNC Monoptes system between the stops set to keep the
383  // objective from running into the walls of the plate. XXX Replace this
384  // with a more meaningful constant, perhaps 0.
385  if (!send_usbmac_command(1, LUDL_SET_LONG_DATA, LUDL_MOTOR_POSITION, 694576)) {
386  REPORT_ERROR("vrpn_LUDL_USBMAC6000::recenter(): Could not send command 2");
387  return false;
388  }
389  channel[0] = 694576;
390 
391  // Send the command to make the Y axis go to both ends of its
392  // range and then move into the center.
393  if (!send_usbmac_command(2, LUDL_MOTOR_ACTION, LUDL_CENTER_HOME, 100000)) {
394  REPORT_ERROR("vrpn_LUDL_USBMAC6000::recenter(): Could not send command 3");
395  return false;
396  }
397  printf("vrpn_LUDL_USBMAC6000::recenter(): Waiting for Y-axis center\n");
398  vrpn_SleepMsecs(500); // XXX Why sleep?
399 
400  // Let libusb handle any outstanding events
401  libusb_handle_events_timeout(_context, &zerotime);
402 
403  flush_input_from_ludl();
404 
405  // First we need to wait for the axis to start moving, then we need
406  // to wait for it to stop moving. This is because sometimes the
407  // X axis (at least) claims to be not moving even though we just
408  // told it to and flushed the buffer
409  while(!ludl_axis_moving(2)) {
410  vrpn_SleepMsecs(10);
411  libusb_handle_events_timeout(_context, &zerotime);
412  }
413  while(ludl_axis_moving(2)) {
414  vrpn_SleepMsecs(10);
415  libusb_handle_events_timeout(_context, &zerotime);
416  }
417 
418  // Send the command to record the value at the center of the Y axis as
419  // 1124201 ticks. This magic number comes from the dividing by two the
420  // range on the UNC Monoptes system between the stops set to keep the
421  // objective from running into the walls of the plate. XXX Replace this
422  // with a more meaningful constant, perhaps 0.
423  if (!send_usbmac_command(2, LUDL_SET_LONG_DATA, LUDL_MOTOR_POSITION, 1124201)) {
424  REPORT_ERROR("vrpn_LUDL_USBMAC6000::recenter(): Could not send command 4");
425  return false;
426  }
427  channel[1] = 1124201;
428 
429  return true;
430 }
431 
432 // I got the algorithm for checking if the axis is moving
433 // from the code in USBMAC6000.cpp from
434 // the video project, as implemented by Ryan Schubert at UNC.
435 // The first axis is 1 in this function.
436 bool vrpn_LUDL_USBMAC6000::ludl_axis_moving(unsigned axis)
437 {
438  // Request the status of the axis. In particular, we look at the
439  // bits telling whether each axis is busy.
440  flush_input_from_ludl();
441  if (!send_usbmac_command(LUDL_INTERFACE_ADDRESS, LUDL_GET_LONG_DATA, LUDL_MODULE_BUSY, 0)) {
442  REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_moving(): Could not send command 1");
443  return false;
444  }
445 
446  // Read from the device to find the status. We call the check_for_data() method
447  // to look for a response.
448  unsigned watchdog = 0;
449  while (_incount == 0) {
450  if (!check_for_data()) {
451  REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_moving(): Could not get report");
452  return false;
453  }
454 
455  // If it has been too long, re-send the request to the stage.
456  // XXX We should not be losing characters... figure out what is causing us to
457  // have to resend.
458  if (++watchdog == 25) { // 25 ms (timeout is 1ms)
459  if (!send_usbmac_command(LUDL_INTERFACE_ADDRESS, LUDL_GET_LONG_DATA, LUDL_MODULE_BUSY, 0)) {
460  REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_moving(): Could not resend command 1");
461  return false;
462  }
463  watchdog = 0;
464  }
465  }
466  int status = 0;
467  int device, command, index;
468  if (!interpret_usbmac_ascii_response(_inbuffer, &device, &command, &index, &status)) {
469  REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_moving(): Could not parse report");
470  return false;
471  }
472  _incount = 0; // XXX Should parse more than one report if there is one.
473  int axisMaskBit = 0x0001 << axis;
474  return (status & axisMaskBit) != 0;
475 }
476 
477 // The first axis is 1 in this function.
478 bool vrpn_LUDL_USBMAC6000::ludl_axis_position(unsigned axis, vrpn_int32 *position_return)
479 {
480  // Request the position of the axis.
481  flush_input_from_ludl();
482  if (!send_usbmac_command(axis, LUDL_GET_LONG_DATA, LUDL_MOTOR_POSITION, 0)) {
483  REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_position(): Could not send command 1");
484  return false;
485  }
486 
487  // Read from the device to find the status. We call the check_for_data() method
488  // to look for a response.
489  unsigned watchdog = 0;
490  while (_incount == 0) {
491  if (!check_for_data()) {
492  REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_position(): Could not get report");
493  return false;
494  }
495 
496  // If it has been too long, re-send the request to the stage.
497  // XXX We should not be losing characters... figure out what is causing us to
498  // have to resend.
499  if (++watchdog == 25) { // 25 ms (timeout is 1ms)
500  if (!send_usbmac_command(axis, LUDL_GET_LONG_DATA, LUDL_MOTOR_POSITION, 0)) {
501  REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_position(): Could not resend command 1");
502  return false;
503  }
504  watchdog = 0;
505  }
506  }
507  int position = 0;
508  int device, command, index;
509  if (!interpret_usbmac_ascii_response(_inbuffer, &device, &command, &index, &position)) {
510  REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_position(): Could not parse report");
511  return false;
512  }
513  _incount = 0; // XXX Should parse more than one report if there is one.
514  if ( (command != LUDL_GET_LONG_DATA) || (index != LUDL_MOTOR_POSITION) ) {
515  REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_position(): Bad command or index in report");
516  return false;
517  }
518  *position_return = position;
519  return true;
520 }
521 
522 bool vrpn_LUDL_USBMAC6000::move_axis_to_position(int axis, int position)
523 {
524  if (!_device_handle) { return false; }
525  if (!_axis_destination || !_axis_moving) { return false; }
526 
527  // If we're already at the place we're being asked to move to,
528  // then we just go ahead and return. Otherwise, the code below
529  // that waits for us to start moving hangs.
530  if (_axis_destination[axis-1] == position) {
531  return true;
532  }
533 
534  // Send the command to the device asking it to move.
535  if (!send_usbmac_command(axis, LUDL_MOTOR_ACTION, LUDL_START_MOTOR_TARGET, position)) {
536  REPORT_ERROR("vrpn_LUDL_USBMAC6000::move_axis_to_position(): Could not send command");
537  return false;
538  }
539 
540  // Wait until that axis starts to move. If we don't do this, then
541  // sometimes we hear back that there are no axes moving even though
542  // we told them to. Just waiting a while after we told them to move
543  // does not help; there is still a report saying that they are not moving.
544  // If the stage is at its limits or if we asked it to go where it already
545  // is, then we'll wait forever here because it will not move. So this
546  // needs to time out and not set the axis to moving if we never see
547  // it start to move.
548  struct timeval start, now;
549  vrpn_gettimeofday(&start, NULL);
550  while (!ludl_axis_moving(axis)) {
551  vrpn_gettimeofday(&now, NULL);
552  struct timeval diff = vrpn_TimevalDiff(now, start);
553  if (diff.tv_sec > 1) {
554  // Say that we moved there, but don't say that the axis is
555  // moving.
556  _axis_destination[axis-1] = position;
557  return true;
558  }
559  };
560 
561  // Indicate that we're expecting this axis to be moving and where we think it is
562  // going, so that when the axis becomes no longer busy we know that we have gotten
563  // there.
564 
565  _axis_destination[axis-1] = position;
566  _axis_moving[axis-1] = true;
567  return true;
568 }
569 
571 {
572  const char *bufptr = p.buffer;
573  vrpn_int32 chan_num;
574  vrpn_int32 pad;
575  vrpn_float64 value;
577 
578  // Read the parameters from the buffer
579  vrpn_unbuffer(&bufptr, &chan_num);
580  vrpn_unbuffer(&bufptr, &pad);
581  vrpn_unbuffer(&bufptr, &value);
582 
583  // Set the position to the appropriate value, if the channel number is in the
584  // range of the ones we have.
585  if ( (chan_num < 0) || (chan_num >= me->o_num_channel) ) {
586  char msg[1024];
587  sprintf(msg,"vrpn_LUDL_USBMAC6000::handle_request_message(): Index out of bounds (%d of %d), value %lg\n",
588  chan_num, me->o_num_channel, value);
590  return 0;
591  }
592 
593  me->move_axis_to_position(chan_num + 1, static_cast<int>(value));
594  return 0;
595 }
596 
598 {
599  int i;
600  const char* bufptr = p.buffer;
601  vrpn_int32 num;
602  vrpn_int32 pad;
604 
605  // Read the values from the buffer
606  vrpn_unbuffer(&bufptr, &num);
607  vrpn_unbuffer(&bufptr, &pad);
608  if (num > me->o_num_channel) {
609  char msg[1024];
610  sprintf(msg,"vrpn_LUDL_USBMAC6000::handle_request_channels_message(): Index out of bounds (%d of %d), clipping\n",
611  num, me->o_num_channel);
613  num = me->o_num_channel;
614  }
615  for (i = 0; i < num; i++) {
616  vrpn_unbuffer(&bufptr, &(me->o_channel[i]));
617  me->move_axis_to_position(i + 1, static_cast<int>(me->o_channel[i]));
618  }
619 
620  return 0;
621 }
622 
626 {
628 
630  return 0;
631 }
632 
633 // End of VRPN_USE_HID
634 #endif
vrpn_LUDL_USBMAC6000::~vrpn_LUDL_USBMAC6000
virtual ~vrpn_LUDL_USBMAC6000()
Definition: vrpn_LUDL.C:153
vrpn_LUDL_USBMAC6000::check_for_data
bool check_for_data()
Definition: vrpn_LUDL.C:169
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_Analog::status
int status
Definition: vrpn_Analog.h:43
vrpn_BaseClass.h
vrpn_BaseClassUnique::d_ping_message_id
vrpn_int32 d_ping_message_id
Ask the server if they are there.
Definition: vrpn_BaseClass.h:230
vrpn_Analog::channel
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:38
vrpn_LUDL_USBMAC6000::handle_connect_message
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:625
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_LUDL_USBMAC6000::_context
struct libusb_context * _context
Definition: vrpn_LUDL.h:49
vrpn_BaseClassUnique::userdata
void * userdata
Definition: vrpn_BaseClass.h:287
vrpn_Analog
Definition: vrpn_Analog.h:28
vrpn_Analog_Output::o_num_channel
vrpn_int32 o_num_channel
Definition: vrpn_Analog_Output.h:37
vrpn_Analog::timestamp
struct timeval timestamp
Definition: vrpn_Analog.h:41
vrpn_Analog_Output
Definition: vrpn_Analog_Output.h:26
vrpn_LUDL_USBMAC6000::mainloop
virtual void mainloop()
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
Definition: vrpn_LUDL.C:207
vrpn_LUDL_USBMAC6000::_inbuffer
vrpn_uint8 _inbuffer[_INBUFFER_SIZE]
Definition: vrpn_LUDL.h:58
vrpn_LUDL_USBMAC6000::_INBUFFER_SIZE
static const unsigned _INBUFFER_SIZE
Definition: vrpn_LUDL.h:57
vrpn_LUDL.h
vrpn_unbuffer
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:312
vrpn_BaseClassUnique::d_connection
vrpn_Connection * d_connection
Connection that this object talks to.
Definition: vrpn_BaseClass.h:224
vrpn_HANDLERPARAM::buffer
const char * buffer
Definition: vrpn_Connection.h:49
vrpn_TEXT_ERROR
@ vrpn_TEXT_ERROR
Definition: vrpn_BaseClass.h:103
vrpn_TimevalDiff
timeval vrpn_TimevalDiff(const timeval &tv1, const timeval &tv2)
Definition: vrpn_Shared.C:92
vrpn_CONNECTION_RELIABLE
const vrpn_uint32 vrpn_CONNECTION_RELIABLE
Classes of service for messages, specify multiple by ORing them together Priority of satisfying these...
Definition: vrpn_Connection.h:120
vrpn_SleepMsecs
void vrpn_SleepMsecs(double dMsecs)
Definition: vrpn_Shared.C:157
vrpn_HANDLERPARAM
This structure is what is passed to a vrpn_Connection message callback.
Definition: vrpn_Connection.h:44
vrpn_BaseClassUnique::d_sender_id
vrpn_int32 d_sender_id
Sender ID registered with the connection.
Definition: vrpn_BaseClass.h:228
vrpn_LUDL_USBMAC6000
Definition: vrpn_LUDL.h:41
vrpn_LUDL_USBMAC6000::handle_request_message
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:570
vrpn_LUDL_USBMAC6000::handle_request_channels_message
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:597
vrpn_LUDL_USBMAC6000::interpret_usbmac_ascii_response
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:321
vrpn_Connection
Generic connection class not specific to the transport mechanism.
Definition: vrpn_Connection.h:510
vrpn_LUDL_USBMAC6000::_endpoint
unsigned _endpoint
Definition: vrpn_LUDL.h:52
vrpn_Analog::num_channel
vrpn_int32 num_channel
Definition: vrpn_Analog.h:40
vrpn_gettimeofday
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
vrpn_LUDL_USBMAC6000::report
void report(vrpn_uint32 class_of_service=vrpn_CONNECTION_RELIABLE)
Definition: vrpn_LUDL.C:255
vrpn_Analog::last
vrpn_float64 last[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:39
vrpn_LUDL_USBMAC6000::_device_handle
struct libusb_device_handle * _device_handle
Definition: vrpn_LUDL.h:50
vrpn_LUDL_USBMAC6000::report_changes
void report_changes(vrpn_uint32 class_of_service=vrpn_CONNECTION_RELIABLE)
Definition: vrpn_LUDL.C:261
vrpn_Analog_Output::o_channel
vrpn_float64 o_channel[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog_Output.h:36
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
REPORT_ERROR
#define REPORT_ERROR(msg)
Definition: vrpn_LUDL.C:27
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_Analog_Output::request_channels_m_id
vrpn_int32 request_channels_m_id
Definition: vrpn_Analog_Output.h:40
vrpn_Analog_Output::request_m_id
vrpn_int32 request_m_id
Definition: vrpn_Analog_Output.h:39
vrpn_LUDL_USBMAC6000::_timestamp
struct timeval _timestamp
Definition: vrpn_LUDL.h:51
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_LUDL_USBMAC6000::_incount
unsigned _incount
Definition: vrpn_LUDL.h:59
vrpn_LUDL_USBMAC6000::vrpn_LUDL_USBMAC6000
vrpn_LUDL_USBMAC6000(const char *name, vrpn_Connection *c=0, bool do_recenter=false)
Definition: vrpn_LUDL.C:48