vrpn  07.33
Virtual Reality Peripheral Network
vrpn_NationalInstruments.C
Go to the documentation of this file.
1 #include <stdio.h> // for sprintf, fprintf, stderr, etc
2 #include "vrpn_Shared.h" // for vrpn_gettimeofday
3 
4 #include "vrpn_BaseClass.h" // for ::vrpn_TEXT_WARNING, etc
5 #include "vrpn_Connection.h" // for vrpn_HANDLERPARAM, etc
7 
8 #ifdef VRPN_USE_NATIONAL_INSTRUMENTS
9 #include "server_src/NIUtil.cpp"
10 #endif
11 
12 
14  const char *boardName,
15  int numInChannels, int numOutChannels,
16  double minInputReportDelaySecs,
17  bool inBipolar, int inputMode, int inputRange, bool driveAIS, int inputGain,
18  bool outBipolar, double minOutVoltage, double maxOutVoltage) :
19  vrpn_Analog(name, c),
20  vrpn_Analog_Output(name, c),
21 #if defined(VRPN_USE_NATIONAL_INSTRUMENTS_MX)
22  d_analog_task_handle(0),
23  d_analog_out_task_handle(0),
24 #else
25  d_device_number(-1),
26 #endif
27  d_out_min_voltage(minOutVoltage),
28  d_out_max_voltage(maxOutVoltage),
29  d_in_min_delay(minInputReportDelaySecs),
30  d_in_gain(inputGain)
31 {
32  // Set the polarity. 0 is bipolar, 1 is unipolar.
33  if (inBipolar) {
34  d_in_polarity = 0;
35  } else {
36  d_in_polarity = 1;
37  }
38  if (outBipolar) {
39  d_out_polarity = 0;
40  } else {
41  d_out_polarity = 1;
42  }
43 
44  setNumInChannels( numInChannels );
45  setNumOutChannels( numOutChannels );
46 
47 #if defined(VRPN_USE_NATIONAL_INSTRUMENTS_MX)
48  char portName[1024];
49  int32 error=0;
50 
51  // Input mode that we are using
52  int32 terminalConfig;
53  switch(inputMode) {
55  terminalConfig = DAQmx_Val_Diff;
56  break;
58  terminalConfig = DAQmx_Val_RSE;
59  break;
61  terminalConfig = DAQmx_Val_NRSE;
62  break;
63  default:
64  fprintf(stderr,"vrpn_National_Instruments_Server::vrpn_National_Instruments_Server(): Invalid inputMode (%d)\n", inputMode);
65  return;
66  }
67 
68  // Minimum and maximum values that we expect to read.
69  // Set the high end of the voltage range. If we're bipolar, then
70  // we get half the range above and half below zero.
71  double min_val = 0.0, max_val = inputRange;
72  if (inBipolar) {
73  min_val = -max_val/2;
74  max_val = max_val/2;
75  }
76 
77  // If we are going analog input, then we specify the range of input
78  // ports that we use from 0 through the number requested. We make a
79  // task to handle reading of these channels as a group. We then
80  // start this task.
81  if (numInChannels > 0) {
82  sprintf(portName, "%s/ai0:%d", boardName, numInChannels-1);
83  error = DAQmxCreateTask("", &d_analog_task_handle);
84  if (error == 0) {
85  error = DAQmxCreateAIVoltageChan(
86  d_analog_task_handle // The handle we'll use to read values
87  , portName // Device name and port range
88  , "" // Our nickname for the channel
89  , terminalConfig // Single-ended vs. differentil
90  , min_val, max_val // Range of values we expect to read
91  , DAQmx_Val_Volts, "" // Units, no custom scale
92  );
93  if (error == 0) {
94  fprintf(stderr,"vrpn_National_Instruments_Server::vrpn_National_Instruments_Server(): Cannot create input voltage channel\n");
95  error = DAQmxStartTask(d_analog_task_handle);
96  }
97  }
98  if (error) {
99  fprintf(stderr,"vrpn_National_Instruments_Server::vrpn_National_Instruments_Server(): Cannot create input voltage task\n");
100  reportError(error);
101  return;
102  }
103  }
104 
105  // If we are going analog output, then we specify the range of output
106  // ports that we use from 0 through the number requested. We make a
107  // task to handle writing of these channels as a group. Start the
108  // task. Also, set the outputs to their minimum value at startup.
109  if (numOutChannels > 0) {
110  sprintf(portName, "%s/ao0:%d", boardName, numOutChannels-1);
111  error = DAQmxCreateTask("", &d_analog_out_task_handle);
112  if (error == 0) {
113  error = DAQmxCreateAOVoltageChan(
114  d_analog_out_task_handle // The handle we'll use to write values
115  , portName // Device name and port range
116  , "" // Our nickname for the channel
117  , minOutVoltage, maxOutVoltage// Range of values we expect to write
118  , DAQmx_Val_Volts, "" // Units, no custom scale
119  );
120  if (error) {
121  fprintf(stderr,"vrpn_National_Instruments_Server::vrpn_National_Instruments_Server(): Cannot create output voltage channel\n");
122  reportError(error);
123  return;
124  }
125  }
126  if (error == 0) {
127  error = DAQmxStartTask(d_analog_out_task_handle);
128  }
129  if (error) {
130  fprintf(stderr,"vrpn_National_Instruments_Server::vrpn_National_Instruments_Server(): Cannot create or start output voltage task\n");
131  reportError(error);
132  return;
133  }
134 
135  // Set the output values to zero or to the minimum if the minimum
136  // is above 0. Also send these values to the board.
137  float64 minval = 0.0;
138  if (minval < minOutVoltage) { minval = minOutVoltage; }
139  int i;
140  for (i = 0; i < vrpn_Analog_Output::o_num_channel; i++) {
141  vrpn_Analog_Output::o_channel[i] = minval;
142  }
143  if (!setValues()) {
144  fprintf(stderr, "vrpn_National_Instruments_Server::vrpn_National_Instruments_Server(): Could not set values\n");
145  return;
146  }
147  }
148 
149 #elif defined(VRPN_USE_NATIONAL_INSTRUMENTS)
150  short i;
151  short update_mode = 0; //< Mode 0 is immediate
152  short ref_source = 0; //< Reference source, 0 = internal, 1 = external
153  double ref_voltage = 10.0;
154 
155  // Open the board
156  d_device_number = NIUtil::findDevice(boardName);
157  if (d_device_number == -1) {
158  fprintf(stderr, "vrpn_National_Instruments_Server: Error opening the D/A board %s\n", boardName);
159  return;
160  }
161 
162  // Set the parameters for each input channel.
163  if (vrpn_Analog::num_channel > 0) {
164  int ret = AI_Clear(d_device_number);
165  if (ret < 0) {
166  fprintf(stderr,"vrpn_National_Instruments_Server: Cannot clear analog input (error %d)\n", ret);
167  setNumInChannels(0);
168  }
169  }
170  for (i = 0; i < vrpn_Analog::num_channel; i++) {
171  int ret = AI_Configure(d_device_number, i, inputMode, inputRange, d_in_polarity, driveAIS);
172  if (ret < 0) {
173  fprintf(stderr,"vrpn_National_Instruments_Server: Cannot configure input channel %d (error %d)\n", i, ret);
174  setNumInChannels(0);
175  break;
176  }
177  }
178 
179  // Set the parameters for each output channel. Set the voltage for each channel to the minimum.
180  for (i = 0; i < o_num_channel; i++) {
181 
182  int ret = AO_Configure(d_device_number, i, d_out_polarity, ref_source, ref_voltage, update_mode);
183  // Code -10403 shows up but did not cause problems for the NI server, so we ignore it (probably at our peril)
184  if ( (ret < 0) && (ret != -10403) ) {
185  fprintf(stderr,"vrpn_National_Instruments_Server: Cannot configure output channel %d (error %d)\n", i, ret);
186  fprintf(stderr," polarity: %d, reference source: %d, reference_voltage: %lg, update_mode: %d\n",
187  d_out_polarity, ref_source, ref_voltage, update_mode);
189  break;
190  }
191 
192  if (AO_VWrite(d_device_number, i, d_out_min_voltage)) {
193  fprintf(stderr,"vrpn_National_Instruments_Server: Cannot set output channel %d to %lg\n", i, d_out_min_voltage);
195  }
196  }
197 
198 #else
199  fprintf(stderr,"vrpn_National_Instruments_Server: Support for NI not compiled in, edit vrpn_Configure.h and recompile VRPN\n");
200 #endif
201 
202  // Check if we have a connection
203  if (d_connection == NULL) {
204  fprintf(stderr, "vrpn_National_Instruments_Server: Can't get connection!\n");
205  }
206 
207  // Register a handler for the request channel change message
210  fprintf(stderr,"vrpn_Analog_Output_Server_NI: can't register change channel request handler\n");
211  d_connection = NULL;
212  }
213 
214  // Register a handler for the request channels change message
217  fprintf(stderr,"vrpn_Analog_Output_Server_NI: can't register change channels request handler\n");
218  d_connection = NULL;
219  }
220 
221  // Register a handler for vrpn_got_connection, so we can tell the
222  // client how many channels are active
224  {
225  fprintf( stderr, "vrpn_Analog_Output_Server_NI: can't register new connection handler\n");
226  d_connection = NULL;
227  }
228 
229  // No report yet sent.
230  d_last_report_time.tv_sec = 0;
231  d_last_report_time.tv_usec = 0;
232 }
233 
234 // virtual
236 {
237 #ifdef VRPN_USE_NATIONAL_INSTRUMENTS_MX
238  if( d_analog_task_handle != 0 )
239  {
240  /*********************************************/
241  // DAQmx Stop Code
242  /*********************************************/
243  DAQmxStopTask(d_analog_task_handle);
244  DAQmxClearTask(d_analog_task_handle);
246  }
247 
248  if( d_analog_out_task_handle != 0 )
249  {
250  /*********************************************/
251  // DAQmx Stop Code
252  /*********************************************/
253  DAQmxStopTask(d_analog_out_task_handle);
254  DAQmxClearTask(d_analog_out_task_handle);
256  }
257 #endif
258 }
259 
260 // virtual
262 {
263  // Let the server code do its thing (ping/pong messages)
264  server_mainloop();
265 
266  // See if it has been long enough since we sent the last report.
267  // If so, then read the channels and send a new report.
268  struct timeval now;
269  vrpn_gettimeofday(&now, NULL);
271  d_last_report_time = now;
272 
273 #if defined(VRPN_USE_NATIONAL_INSTRUMENTS_MX)
274  // Read one complete set of channel values from the board and store
275  // the results (which are already in volts) into the channels.
276  if (vrpn_Analog::num_channel > 0) {
277  int32 error;
278  int32 channelsRead = 0;
279  float64 data[vrpn_CHANNEL_MAX];
280  error = DAQmxReadAnalogF64(d_analog_task_handle, 1, 1.0, DAQmx_Val_GroupByChannel,
281  data, vrpn_CHANNEL_MAX, &channelsRead, NULL);
282  if (channelsRead != vrpn_Analog::num_channel) {
283  send_text_message("vrpn_National_Instruments_Server::mainloop(): Cannot read channel", now, vrpn_TEXT_ERROR);
284  setNumInChannels(0);
285  return;
286  }
287  if (error) {
288  reportError(error);
289  return;
290  }
291  int i;
292  for (i = 0; i < channelsRead; i++) {
293  channel[i] = data[i];
294  }
295  }
296 
297 #elif defined(VRPN_USE_NATIONAL_INSTRUMENTS)
298  // Read from the board, convert to volts, and store in the channel array
299  i16 value;
300  int i;
301  for (i = 0; i < vrpn_Analog::num_channel; i++) {
302  int ret = AI_Read(d_device_number, i, d_in_gain, &value);
303  if (ret != 0) {
304  send_text_message("vrpn_National_Instruments_Server::mainloop(): Cannot read channel", now, vrpn_TEXT_ERROR);
305  setNumInChannels(0);
306  return;
307  }
308  if(0 == d_in_polarity){ //Bipolar: We multiply by 10, but it will only go halfway (it is signed).
309  channel[i] = (value / 65536.0) * (10.0 / d_in_gain);
310  } else { //Unipolar (cast it to unsigned, so it will be from zero to almost 10 volts).
311  channel[i] = ((vrpn_uint16)value / 65536.0) * (10.0 / d_in_gain);
312  }
313  }
314 #endif
315 
316  // Send a report.
318  }
319 }
320 
322  if (sizeRequested < 0) sizeRequested = 0;
323  if (sizeRequested > vrpn_CHANNEL_MAX) sizeRequested = vrpn_CHANNEL_MAX;
324  vrpn_Analog::num_channel = sizeRequested;
325 
327 }
328 
330  if (sizeRequested < 0) sizeRequested = 0;
331  if (sizeRequested > vrpn_CHANNEL_MAX) sizeRequested = vrpn_CHANNEL_MAX;
332 
333  o_num_channel = sizeRequested;
334  return o_num_channel;
335 }
336 
337 /* static */
340 {
341  const char* bufptr = p.buffer;
342  vrpn_int32 chan_num;
343  vrpn_int32 pad;
344  vrpn_float64 value;
346 
347  // Read the parameters from the buffer
348  vrpn_unbuffer(&bufptr, &chan_num);
349  vrpn_unbuffer(&bufptr, &pad);
350  vrpn_unbuffer(&bufptr, &value);
351 
352  // Set the appropriate value, if the channel number is in the
353  // range of the ones we have.
354  if ( (chan_num < 0) || (chan_num >= me->o_num_channel) ) {
355  char msg[1024];
356  sprintf( msg, "Error: (handle_request_message): channel %d is not active. Squelching.", chan_num );
358  return 0;
359  }
360  // Make sure the voltage value is within the allowed range.
361  if (value < me->d_out_min_voltage) {
362  char msg[1024];
363  sprintf( msg, "Error: (handle_request_message): voltage %g is too low. Clamping to %g.", value, me->d_out_min_voltage);
365  value = me->d_out_min_voltage;
366  }
367  if (value > me->d_out_max_voltage) {
368  char msg[1024];
369  sprintf( msg, "Error: (handle_request_message): voltage %g is too high. Clamping to %g.", value, me->d_out_max_voltage);
371  value = me->d_out_max_voltage;
372  }
373  me->o_channel[chan_num] = value;
374 
375  // Send the new value to the D/A board
376 #if defined(VRPN_USE_NATIONAL_INSTRUMENTS_MX)
377  if (!me->setValues()) {
378  me->send_text_message( "vrpn_National_Instruments_Server::handle_request_message(): Could not set values", p.msg_time, vrpn_TEXT_ERROR );
379  return -1;
380  }
381 
382 #elif defined(VRPN_USE_NATIONAL_INSTRUMENTS)
383  if (me->d_device_number != -1) {
384  AO_VWrite(me->d_device_number, (short)(chan_num), value);
385  }
386 #endif
387  return 0;
388 }
389 
390 /* static */
393 {
394  const char* bufptr = p.buffer;
395  vrpn_int32 num;
396  vrpn_int32 pad;
398  vrpn_int32 chan_num;
399  vrpn_float64 value;
400 
401  // Read the values from the buffer
402  vrpn_unbuffer(&bufptr, &num);
403  vrpn_unbuffer(&bufptr, &pad);
404  if (num > me->o_num_channel)
405  {
406  char msg[1024];
407  sprintf( msg, "Error: (handle_request_channels_message): channels above %d not active; "
408  "bad request up to channel %d. Squelching.", me->o_num_channel, num );
410  num = me->o_num_channel;
411  }
412  if (num < 0)
413  {
414  char msg[1024];
415  sprintf( msg, "Error: (handle_request_channels_message): invalid channel %d. Squelching.", num );
417  return 0;
418  }
419  for (chan_num = 0; chan_num < num; chan_num++) {
420  vrpn_unbuffer(&bufptr, &value);
421 
422  // Make sure the voltage value is within the allowed range.
423  if (value < me->d_out_min_voltage) {
424  char msg[1024];
425  sprintf( msg, "Error: (handle_request_messages): voltage %g is too low. Clamping to %g.", value, me->d_out_min_voltage);
427  value = me->d_out_min_voltage;
428  }
429  if (value > me->d_out_max_voltage) {
430  char msg[1024];
431  sprintf( msg, "Error: (handle_request_messages): voltage %g is too high. Clamping to %g.", value, me->d_out_max_voltage);
433  value = me->d_out_max_voltage;
434  }
435  me->o_channel[chan_num] = value;
436 
437  // Send the new value to the D/A board
438 #ifdef VRPN_USE_NATIONAL_INSTRUMENTS
439  if (me->d_device_number != -1) {
440  AO_VWrite(me->d_device_number, (short)(chan_num), value);
441  }
442 #endif
443  }
444 
445 #if defined(VRPN_USE_NATIONAL_INSTRUMENTS_MX)
446  if (!me->setValues()) {
447  me->send_text_message( "vrpn_National_Instruments_Server::handle_request_channels_message(): Could not set values", p.msg_time, vrpn_TEXT_ERROR );
448  return -1;
449  }
450 #endif
451 
452  return 0;
453 }
454 
455 #if defined(VRPN_USE_NATIONAL_INSTRUMENTS_MX)
457  // Send all current values to the board, including the
458  // changed one.
459  float64 outbuffer[vrpn_CHANNEL_MAX];
460  int i;
461  for (i = 0; i < vrpn_Analog_Output::o_num_channel ; i++) {
462  outbuffer[i] = vrpn_Analog_Output::o_channel[i];
463  }
464  int32 error;
465  error = DAQmxWriteAnalogF64(d_analog_out_task_handle, 1, true, 1.0,
466  DAQmx_Val_GroupByChannel, outbuffer, NULL, NULL);
467  if (error) {
468  reportError(error);
469  return false;
470  }
471  /*
472  printf("Debug: Setting %d channels:", o_num_channel);
473  for (i = 0; i < o_num_channel; i++) {
474  printf(" %lg", outbuffer[i]);
475  }
476  printf("\n");
477  */
478  return true;
479 }
480 #endif
481 
482 /* static */
484 {
486  if( me->report_num_channels( ) == false ) {
487  fprintf( stderr, "Error: failed sending active channels to client.\n" );
488  }
489  return 0;
490 }
491 
492 bool vrpn_National_Instruments_Server::report_num_channels( vrpn_uint32 class_of_service )
493 {
494  char msgbuf[ sizeof( vrpn_int32) ];
495  vrpn_int32 len = sizeof( vrpn_int32 );;
496 
498  vrpn_gettimeofday( &o_timestamp, NULL );
499  if( d_connection &&
501  d_sender_id, msgbuf, class_of_service ) )
502  {
503  fprintf(stderr, "vrpn_Analog_Output_Server_NI (report_num_channels): cannot write message: tossing\n");
504  return false;
505  }
506  return true;
507 }
508 
509 
510 vrpn_int32 vrpn_National_Instruments_Server::encode_num_channels_to( char* buf, vrpn_int32 num )
511 {
512  // Message includes: int32 number of active channels
513  int buflen = sizeof(vrpn_int32);
514 
515  vrpn_buffer(&buf, &buflen, num);
516  return sizeof(vrpn_int32);
517 }
518 
520  const char *boardName,
521  vrpn_int16 numChannels, bool bipolar,
522  double minVoltage, double maxVoltage) :
523  vrpn_Analog_Output(name, c),
524  NI_device_number(-1),
525  min_voltage(minVoltage),
526  max_voltage(maxVoltage),
527  NI_num_channels(numChannels)
528 {
529 #ifdef VRPN_USE_NATIONAL_INSTRUMENTS
530  short i;
531  short update_mode = 0; //< Mode 0 is immediate
532  short ref_source = 0; //< Reference source, 0 = internal, 1 = external
533  double ref_voltage = 0.0;
534 
535  // Set the polarity
536  if (bipolar) {
537  polarity = 0;
538  } else {
539  polarity = 1;
540  }
541 
542  // Open the D/A board and set the parameters for each channel. Set the voltage for each
543  // channel to the minimum.
544  NI_device_number = NIUtil::findDevice(boardName);
545  if (NI_device_number == -1) {
546  fprintf(stderr, "vrpn_Analog_Output_Server_NI: Error opening the D/A board %s\n", boardName);
547  return;
548  }
549  for (i = 0; i < NI_num_channels; i++) {
550  AO_Configure(NI_device_number, i, polarity, ref_source, ref_voltage,
551  update_mode);
552 /*
553  fprintf(stderr,"Configuring channel %d, polarity: %d, reference source: %d, reference_voltage: %lg, update_mode: %d\n",
554  i, polarity, ref_source, ref_voltage, update_mode);
555 */
556  AO_VWrite(NI_device_number, i, min_voltage);
557  }
558 
559 
560  setNumChannels( numChannels );
561 
562  // Check if we have a connection
563  if (d_connection == NULL) {
564  fprintf(stderr, "vrpn_Analog_Output_Server_NI: Can't get connection!\n");
565  }
566 
567  // Register a handler for the request channel change message
570  fprintf(stderr,"vrpn_Analog_Output_Server_NI: can't register change channel request handler\n");
571  d_connection = NULL;
572  }
573 
574  // Register a handler for the request channels change message
577  fprintf(stderr,"vrpn_Analog_Output_Server_NI: can't register change channels request handler\n");
578  d_connection = NULL;
579  }
580 
581  // Register a handler for vrpn_got_connection, so we can tell the
582  // client how many channels are active
584  {
585  fprintf( stderr, "vrpn_Analog_Output_Server_NI: can't register new connection handler\n");
586  d_connection = NULL;
587  }
588 #else
589  fprintf(stderr,"vrpn_Analog_Output_Server_NI: Support for NI not compiled in, edit vrpn_Configure.h and recompile\n");
590 #endif
591 }
592 
593 // virtual
595 
596 // virtual
598 {
599  // Let the server code do its thing (ping/pong messages)
600  server_mainloop();
601 }
602 
603 vrpn_int32 vrpn_Analog_Output_Server_NI::setNumChannels (vrpn_int32 sizeRequested) {
604  if (sizeRequested < 0) sizeRequested = 0;
605  if (sizeRequested > vrpn_CHANNEL_MAX) sizeRequested = vrpn_CHANNEL_MAX;
606 
607  o_num_channel = sizeRequested;
608 
609  return o_num_channel;
610 }
611 
612 /* static */
615 {
616  const char* bufptr = p.buffer;
617  vrpn_int32 chan_num;
618  vrpn_int32 pad;
619  vrpn_float64 value;
621 
622  // Read the parameters from the buffer
623  vrpn_unbuffer(&bufptr, &chan_num);
624  vrpn_unbuffer(&bufptr, &pad);
625  vrpn_unbuffer(&bufptr, &value);
626 
627  // Set the appropriate value, if the channel number is in the
628  // range of the ones we have.
629  if ( (chan_num < 0) || (chan_num >= me->o_num_channel) ) {
630  char msg[1024];
631  sprintf( msg, "Error: (handle_request_message): channel %d is not active. Squelching.", chan_num );
633  return 0;
634  }
635  // Make sure the voltage value is within the allowed range.
636  if (value < me->min_voltage) {
637  char msg[1024];
638  sprintf( msg, "Error: (handle_request_message): voltage %g is too low. Clamping to %g.", value, me->min_voltage);
640  value = me->min_voltage;
641  }
642  if (value > me->max_voltage) {
643  char msg[1024];
644  sprintf( msg, "Error: (handle_request_message): voltage %g is too high. Clamping to %g.", value, me->max_voltage);
646  value = me->max_voltage;
647  }
648  me->o_channel[chan_num] = value;
649 
650  // Send the new value to the D/A board
651 #ifdef VRPN_USE_NATIONAL_INSTRUMENTS
652  if (me->NI_device_number != -1) {
653  AO_VWrite(me->NI_device_number, (short)(chan_num), value);
654  }
655 #endif
656  return 0;
657 }
658 
659 /* static */
662 {
663  const char* bufptr = p.buffer;
664  vrpn_int32 num;
665  vrpn_int32 pad;
667  vrpn_int32 chan_num;
668  vrpn_float64 value;
669 
670  // Read the values from the buffer
671  vrpn_unbuffer(&bufptr, &num);
672  vrpn_unbuffer(&bufptr, &pad);
673  if (num > me->o_num_channel)
674  {
675  char msg[1024];
676  sprintf( msg, "Error: (handle_request_channels_message): channels above %d not active; "
677  "bad request up to channel %d. Squelching.", me->o_num_channel, num );
679  num = me->o_num_channel;
680  }
681  if (num < 0)
682  {
683  char msg[1024];
684  sprintf( msg, "Error: (handle_request_channels_message): invalid channel %d. Squelching.", num );
686  return 0;
687  }
688  for (chan_num = 0; chan_num < num; chan_num++) {
689  vrpn_unbuffer(&bufptr, &value);
690 
691  // Make sure the voltage value is within the allowed range.
692  if (value < me->min_voltage) {
693  char msg[1024];
694  sprintf( msg, "Error: (handle_request_messages): voltage %g is too low. Clamping to %g.", value, me->min_voltage);
696  value = me->min_voltage;
697  }
698  if (value > me->max_voltage) {
699  char msg[1024];
700  sprintf( msg, "Error: (handle_request_messages): voltage %g is too high. Clamping to %g.", value, me->max_voltage);
702  value = me->max_voltage;
703  }
704  me->o_channel[chan_num] = value;
705 
706  // Send the new value to the D/A board
707 #ifdef VRPN_USE_NATIONAL_INSTRUMENTS
708  if (me->NI_device_number != -1) {
709  AO_VWrite(me->NI_device_number, (short)(chan_num), value);
710  }
711 #endif
712  }
713 
714  return 0;
715 }
716 
717 
718 /* static */
720 {
722  if( me->report_num_channels( ) == false )
723  {
724  fprintf( stderr, "Error: failed sending active channels to client.\n" );
725  }
726  return 0;
727 }
728 
729 
730 bool vrpn_Analog_Output_Server_NI::report_num_channels( vrpn_uint32 class_of_service )
731 {
732  char msgbuf[ sizeof( vrpn_int32) ];
733  vrpn_int32 len = sizeof( vrpn_int32 );;
734 
736  vrpn_gettimeofday( &o_timestamp, NULL );
737  if( d_connection &&
739  d_sender_id, msgbuf, class_of_service ) )
740  {
741  fprintf(stderr, "vrpn_Analog_Output_Server_NI (report_num_channels): cannot write message: tossing\n");
742  return false;
743  }
744  return true;
745 }
746 
747 
749 encode_num_channels_to( char* buf, vrpn_int32 num )
750 {
751  // Message includes: int32 number of active channels
752  int buflen = sizeof(vrpn_int32);
753 
754  vrpn_buffer(&buf, &buflen, num);
755  return sizeof(vrpn_int32);
756 }
757 
758 // This handles error reporting
759 #ifdef VRPN_USE_NATIONAL_INSTRUMENTS_MX
760 void vrpn_National_Instruments_Server::reportError(int32 errnumber, vrpn_bool exitProgram)
761 {
762  char errBuff[2048]={'\0'};
763 
764  if( DAQmxFailed(errnumber) )
765  {
766  DAQmxGetExtendedErrorInfo(errBuff,2048);
767  printf("DAQmx Error: %s\n",errBuff);
768  if (exitProgram==vrpn_true) {
769  printf("Exiting...\n") ;
770  throw(errnumber) ; // this will quit, cause the destructor to be called
771  } else {
772  printf("Sleeping...\n") ;
773  vrpn_SleepMsecs(1000.0*1) ; // so at least the log will slow down so someone can see the error
774  }
775  }
776 } // reportError
777 #endif
void server_mainloop(void)
Handles functions that all servers should provide in their mainloop() (ping/pong, for example) Should...
virtual vrpn_int32 encode_num_channels_to(char *buf, vrpn_int32 num)
struct timeval msg_time
struct timeval o_timestamp
void vrpn_SleepMsecs(double dMsecs)
Definition: vrpn_Shared.C:157
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_int32 request_channels_m_id
virtual vrpn_int32 encode_num_channels_to(char *buf, vrpn_int32 num)
static int VRPN_CALLBACK handle_got_connection(void *userdata, vrpn_HANDLERPARAM p)
Used to notify us when a new connection is requested, so that we can let the client know how many cha...
int setNumOutChannels(int sizeRequested)
Sets the size of the array; returns the size actually set. (May be clamped to vrpn_CHANNEL_MAX) This ...
const char * buffer
vrpn_float64 o_channel[vrpn_CHANNEL_MAX]
vrpn_National_Instruments_Server(const char *name, vrpn_Connection *c, const char *boardName="PCI-6713", int numInChannels=vrpn_CHANNEL_MAX, int numOutChannels=vrpn_CHANNEL_MAX, double minInputReportDelaySecs=0.0, bool inBipolar=false, int inputMode=vrpn_NI_INPUT_MODE_DIFFERENTIAL, int inputRange=vrpn_NI_INPUT_RANGE_10V, bool driveAIS=false, int inputGain=1, bool outBipolar=false, double minOutVoltage=0.0, double maxOutVoltage=10.0)
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:38
virtual void mainloop()
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
virtual bool report_num_channels(vrpn_uint32 class_of_service=vrpn_CONNECTION_RELIABLE)
Generic connection class not specific to the transport mechanism.
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
#define VRPN_CALLBACK
int setNumInChannels(int sizeRequested)
Sets the size of the array; returns the size actually set. (May be clamped to vrpn_CHANNEL_MAX) This ...
virtual bool report_num_channels(vrpn_uint32 class_of_service=vrpn_CONNECTION_RELIABLE)
All types of client/server/peer objects in VRPN should be derived from the vrpn_BaseClass type descri...
double vrpn_TimevalDurationSeconds(struct timeval endT, struct timeval startT)
Return the number of seconds between startT and endT as a floating-point value.
Definition: vrpn_Shared.C:135
static int VRPN_CALLBACK handle_got_connection(void *userdata, vrpn_HANDLERPARAM p)
Used to notify us when a new connection is requested, so that we can let the client know how many cha...
vrpn_int32 num_channel
Definition: vrpn_Analog.h:40
static int VRPN_CALLBACK handle_request_channels_message(void *userdata, vrpn_HANDLERPARAM p)
Responds to a request to change a number of channels Derived class must either install handlers for t...
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.
virtual void mainloop()
Called once through each main loop iteration to handle updates. Remote object mainloop() should call ...
vrpn_Connection * d_connection
Connection that this object talks to.
This structure is what is passed to a vrpn_Connection message callback.
virtual int pack_message(vrpn_uint32 len, struct timeval time, vrpn_int32 type, vrpn_int32 sender, const char *buffer, vrpn_uint32 class_of_service)
Pack a message that will be sent the next time mainloop() is called. Turn off the RELIABLE flag if yo...
vrpn_int32 got_connection_m_id
vrpn_int32 setNumChannels(vrpn_int32 sizeRequested)
Sets the size of the array; returns the size actually set. (May be clamped to vrpn_CHANNEL_MAX) This ...
vrpn_int32 report_num_channels_m_id
static int VRPN_CALLBACK handle_request_channels_message(void *userdata, vrpn_HANDLERPARAM p)
Responds to a request to change a number of channels Derived class must either install handlers for t...
#define vrpn_NI_INPUT_MODE_DIFFERENTIAL
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.
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
VRPN_API int vrpn_buffer(char **insertPt, vrpn_int32 *buflen, const timeval t)
Utility routine for placing a timeval struct into a buffer that is to be sent as a message...
Definition: vrpn_Shared.C:241
#define vrpn_CHANNEL_MAX
Definition: vrpn_Analog.h:16
vrpn_int32 d_sender_id
Sender ID registered with the connection.
#define vrpn_NI_INPUT_MODE_NON_REF_SINGLE_ENDED
void reportError(int32 errnumber, vrpn_bool exitProgram=vrpn_false)
static int VRPN_CALLBACK handle_request_message(void *userdata, vrpn_HANDLERPARAM p)
Responds to a request to the AnalogOutput to change one of the values by setting the channel to that ...
vrpn_Analog_Output_Server_NI(const char *name, vrpn_Connection *c, const char *boardName="PCI-6713", vrpn_int16 numChannels=vrpn_CHANNEL_MAX, bool bipolar=false, double minVoltage=0.0, double maxVoltage=10.0)
#define vrpn_NI_INPUT_MODE_REF_SINGLE_ENDED
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. Derived class must either install handlers for this routine or else make its own routines to handle the request message.