Something went wrong on our end
vrpn_NationalInstruments.C 26.34 KiB
#include <stdio.h> // for sprintf, fprintf, stderr, etc
#include "vrpn_Shared.h" // for vrpn_gettimeofday
#include "vrpn_BaseClass.h" // for ::vrpn_TEXT_WARNING, etc
#include "vrpn_Connection.h" // for vrpn_HANDLERPARAM, etc
#include "vrpn_NationalInstruments.h"
#ifdef VRPN_USE_NATIONAL_INSTRUMENTS
#include "server_src/NIUtil.cpp"
#endif
vrpn_National_Instruments_Server::vrpn_National_Instruments_Server (const char* name, vrpn_Connection * c,
const char *boardName,
int numInChannels, int numOutChannels,
double minInputReportDelaySecs,
bool inBipolar, int inputMode, int inputRange, bool driveAIS, int inputGain,
bool outBipolar, double minOutVoltage, double maxOutVoltage) :
vrpn_Analog(name, c),
vrpn_Analog_Output(name, c),
#if defined(VRPN_USE_NATIONAL_INSTRUMENTS_MX)
d_analog_task_handle(0),
d_analog_out_task_handle(0),
#else
d_device_number(-1),
#endif
d_out_min_voltage(minOutVoltage),
d_out_max_voltage(maxOutVoltage),
d_in_min_delay(minInputReportDelaySecs),
d_in_gain(inputGain)
{
// Set the polarity. 0 is bipolar, 1 is unipolar.
if (inBipolar) {
d_in_polarity = 0;
} else {
d_in_polarity = 1;
}
if (outBipolar) {
d_out_polarity = 0;
} else {
d_out_polarity = 1;
}
setNumInChannels( numInChannels );
setNumOutChannels( numOutChannels );
#if defined(VRPN_USE_NATIONAL_INSTRUMENTS_MX)
char portName[1024];
int32 error=0;
// Input mode that we are using
int32 terminalConfig;
switch(inputMode) {
case vrpn_NI_INPUT_MODE_DIFFERENTIAL:
terminalConfig = DAQmx_Val_Diff;
break;
case vrpn_NI_INPUT_MODE_REF_SINGLE_ENDED:
terminalConfig = DAQmx_Val_RSE;
break;
case vrpn_NI_INPUT_MODE_NON_REF_SINGLE_ENDED:
terminalConfig = DAQmx_Val_NRSE;
break;
default:
fprintf(stderr,"vrpn_National_Instruments_Server::vrpn_National_Instruments_Server(): Invalid inputMode (%d)\n", inputMode);
return;
}
// Minimum and maximum values that we expect to read.
// Set the high end of the voltage range. If we're bipolar, then
// we get half the range above and half below zero.
double min_val = 0.0, max_val = inputRange;
if (inBipolar) {
min_val = -max_val/2;
max_val = max_val/2;
}
// If we are going analog input, then we specify the range of input
// ports that we use from 0 through the number requested. We make a
// task to handle reading of these channels as a group. We then
// start this task.
if (numInChannels > 0) {
sprintf(portName, "%s/ai0:%d", boardName, numInChannels-1);
error = DAQmxCreateTask("", &d_analog_task_handle);
if (error == 0) {
error = DAQmxCreateAIVoltageChan(
d_analog_task_handle // The handle we'll use to read values
, portName // Device name and port range
, "" // Our nickname for the channel
, terminalConfig // Single-ended vs. differentil
, min_val, max_val // Range of values we expect to read
, DAQmx_Val_Volts, "" // Units, no custom scale
);
if (error == 0) {
fprintf(stderr,"vrpn_National_Instruments_Server::vrpn_National_Instruments_Server(): Cannot create input voltage channel\n");
error = DAQmxStartTask(d_analog_task_handle);
}
}
if (error) {
fprintf(stderr,"vrpn_National_Instruments_Server::vrpn_National_Instruments_Server(): Cannot create input voltage task\n");
reportError(error);
return;
}
}
// If we are going analog output, then we specify the range of output
// ports that we use from 0 through the number requested. We make a
// task to handle writing of these channels as a group. Start the
// task. Also, set the outputs to their minimum value at startup.
if (numOutChannels > 0) {
sprintf(portName, "%s/ao0:%d", boardName, numOutChannels-1);
error = DAQmxCreateTask("", &d_analog_out_task_handle);
if (error == 0) {
error = DAQmxCreateAOVoltageChan(
d_analog_out_task_handle // The handle we'll use to write values
, portName // Device name and port range
, "" // Our nickname for the channel
, minOutVoltage, maxOutVoltage// Range of values we expect to write
, DAQmx_Val_Volts, "" // Units, no custom scale
);
if (error) {
fprintf(stderr,"vrpn_National_Instruments_Server::vrpn_National_Instruments_Server(): Cannot create output voltage channel\n");
reportError(error);
return;
}
}
if (error == 0) {
error = DAQmxStartTask(d_analog_out_task_handle);
}
if (error) {
fprintf(stderr,"vrpn_National_Instruments_Server::vrpn_National_Instruments_Server(): Cannot create or start output voltage task\n");
reportError(error);
return;
}
// Set the output values to zero or to the minimum if the minimum
// is above 0. Also send these values to the board.
float64 minval = 0.0;
if (minval < minOutVoltage) { minval = minOutVoltage; }
int i;
for (i = 0; i < vrpn_Analog_Output::o_num_channel; i++) {
vrpn_Analog_Output::o_channel[i] = minval;
}
if (!setValues()) {
fprintf(stderr, "vrpn_National_Instruments_Server::vrpn_National_Instruments_Server(): Could not set values\n");
return;
}
}
#elif defined(VRPN_USE_NATIONAL_INSTRUMENTS)
short i;
short update_mode = 0; //< Mode 0 is immediate
short ref_source = 0; //< Reference source, 0 = internal, 1 = external
double ref_voltage = 10.0;
// Open the board
d_device_number = NIUtil::findDevice(boardName);
if (d_device_number == -1) {
fprintf(stderr, "vrpn_National_Instruments_Server: Error opening the D/A board %s\n", boardName);
return;
}
// Set the parameters for each input channel.
if (vrpn_Analog::num_channel > 0) {
int ret = AI_Clear(d_device_number);
if (ret < 0) {
fprintf(stderr,"vrpn_National_Instruments_Server: Cannot clear analog input (error %d)\n", ret);
setNumInChannels(0);
}
}
for (i = 0; i < vrpn_Analog::num_channel; i++) {
int ret = AI_Configure(d_device_number, i, inputMode, inputRange, d_in_polarity, driveAIS);
if (ret < 0) {
fprintf(stderr,"vrpn_National_Instruments_Server: Cannot configure input channel %d (error %d)\n", i, ret);
setNumInChannels(0);
break;
}
}
// Set the parameters for each output channel. Set the voltage for each channel to the minimum.
for (i = 0; i < o_num_channel; i++) {
int ret = AO_Configure(d_device_number, i, d_out_polarity, ref_source, ref_voltage, update_mode);
// Code -10403 shows up but did not cause problems for the NI server, so we ignore it (probably at our peril)
if ( (ret < 0) && (ret != -10403) ) {
fprintf(stderr,"vrpn_National_Instruments_Server: Cannot configure output channel %d (error %d)\n", i, ret);
fprintf(stderr," polarity: %d, reference source: %d, reference_voltage: %lg, update_mode: %d\n",
d_out_polarity, ref_source, ref_voltage, update_mode);
setNumOutChannels(0);
break;
}
if (AO_VWrite(d_device_number, i, d_out_min_voltage)) {
fprintf(stderr,"vrpn_National_Instruments_Server: Cannot set output channel %d to %lg\n", i, d_out_min_voltage);
setNumOutChannels(0);
}
}
#else
fprintf(stderr,"vrpn_National_Instruments_Server: Support for NI not compiled in, edit vrpn_Configure.h and recompile VRPN\n");
#endif
// Check if we have a connection
if (d_connection == NULL) {
fprintf(stderr, "vrpn_National_Instruments_Server: Can't get connection!\n");
}
// Register a handler for the request channel change message
if (register_autodeleted_handler(request_m_id,
handle_request_message, this, d_sender_id)) {
fprintf(stderr,"vrpn_Analog_Output_Server_NI: can't register change channel request handler\n");
d_connection = NULL;
}
// Register a handler for the request channels change message
if (register_autodeleted_handler(request_channels_m_id,
handle_request_channels_message, this, d_sender_id)) {
fprintf(stderr,"vrpn_Analog_Output_Server_NI: can't register change channels request handler\n");
d_connection = NULL;
}
// Register a handler for vrpn_got_connection, so we can tell the
// client how many channels are active
if( register_autodeleted_handler( got_connection_m_id, handle_got_connection, this ) )
{
fprintf( stderr, "vrpn_Analog_Output_Server_NI: can't register new connection handler\n");
d_connection = NULL;
}
// No report yet sent.
d_last_report_time.tv_sec = 0;
d_last_report_time.tv_usec = 0;
}
// virtual
vrpn_National_Instruments_Server::~vrpn_National_Instruments_Server()
{
#ifdef VRPN_USE_NATIONAL_INSTRUMENTS_MX
if( d_analog_task_handle != 0 )
{
/*********************************************/
// DAQmx Stop Code
/*********************************************/
DAQmxStopTask(d_analog_task_handle);
DAQmxClearTask(d_analog_task_handle);
d_analog_task_handle = 0 ;
}
if( d_analog_out_task_handle != 0 )
{
/*********************************************/
// DAQmx Stop Code
/*********************************************/
DAQmxStopTask(d_analog_out_task_handle);
DAQmxClearTask(d_analog_out_task_handle);
d_analog_out_task_handle = 0 ;
}
#endif
}
// virtual
void vrpn_National_Instruments_Server::mainloop(void)
{
// Let the server code do its thing (ping/pong messages)
server_mainloop();
// See if it has been long enough since we sent the last report.
// If so, then read the channels and send a new report.
struct timeval now;
vrpn_gettimeofday(&now, NULL);
if (vrpn_TimevalDurationSeconds(now, d_last_report_time) >= d_in_min_delay) {
d_last_report_time = now;
#if defined(VRPN_USE_NATIONAL_INSTRUMENTS_MX)
// Read one complete set of channel values from the board and store
// the results (which are already in volts) into the channels.
if (vrpn_Analog::num_channel > 0) {
int32 error;
int32 channelsRead = 0;
float64 data[vrpn_CHANNEL_MAX];
error = DAQmxReadAnalogF64(d_analog_task_handle, 1, 1.0, DAQmx_Val_GroupByChannel,
data, vrpn_CHANNEL_MAX, &channelsRead, NULL);
if (channelsRead != vrpn_Analog::num_channel) {
send_text_message("vrpn_National_Instruments_Server::mainloop(): Cannot read channel", now, vrpn_TEXT_ERROR);
setNumInChannels(0);
return;
}
if (error) {
reportError(error);
return;
}
int i;
for (i = 0; i < channelsRead; i++) {
channel[i] = data[i];
}
}
#elif defined(VRPN_USE_NATIONAL_INSTRUMENTS)
// Read from the board, convert to volts, and store in the channel array
i16 value;
int i;
for (i = 0; i < vrpn_Analog::num_channel; i++) {
int ret = AI_Read(d_device_number, i, d_in_gain, &value);
if (ret != 0) {
send_text_message("vrpn_National_Instruments_Server::mainloop(): Cannot read channel", now, vrpn_TEXT_ERROR);
setNumInChannels(0);
return;
}
if(0 == d_in_polarity){ //Bipolar: We multiply by 10, but it will only go halfway (it is signed).
channel[i] = (value / 65536.0) * (10.0 / d_in_gain);
} else { //Unipolar (cast it to unsigned, so it will be from zero to almost 10 volts).
channel[i] = ((vrpn_uint16)value / 65536.0) * (10.0 / d_in_gain);
}
}
#endif
// Send a report.
vrpn_Analog::report();
}
}
int vrpn_National_Instruments_Server::setNumInChannels (int sizeRequested) {
if (sizeRequested < 0) sizeRequested = 0;
if (sizeRequested > vrpn_CHANNEL_MAX) sizeRequested = vrpn_CHANNEL_MAX;
vrpn_Analog::num_channel = sizeRequested;
return vrpn_Analog::num_channel;
}
int vrpn_National_Instruments_Server::setNumOutChannels (int sizeRequested) {
if (sizeRequested < 0) sizeRequested = 0;
if (sizeRequested > vrpn_CHANNEL_MAX) sizeRequested = vrpn_CHANNEL_MAX;
o_num_channel = sizeRequested;
return o_num_channel;
}
/* static */
int VRPN_CALLBACK vrpn_National_Instruments_Server::handle_request_message(void *userdata,
vrpn_HANDLERPARAM p)
{
const char* bufptr = p.buffer;
vrpn_int32 chan_num;
vrpn_int32 pad;
vrpn_float64 value;
vrpn_National_Instruments_Server* me = (vrpn_National_Instruments_Server*)userdata;
// Read the parameters from the buffer
vrpn_unbuffer(&bufptr, &chan_num);
vrpn_unbuffer(&bufptr, &pad);
vrpn_unbuffer(&bufptr, &value);
// Set the appropriate value, if the channel number is in the
// range of the ones we have.
if ( (chan_num < 0) || (chan_num >= me->o_num_channel) ) {
char msg[1024];
sprintf( msg, "Error: (handle_request_message): channel %d is not active. Squelching.", chan_num );
me->send_text_message( msg, p.msg_time, vrpn_TEXT_ERROR );
return 0;
}
// Make sure the voltage value is within the allowed range.
if (value < me->d_out_min_voltage) {
char msg[1024];
sprintf( msg, "Error: (handle_request_message): voltage %g is too low. Clamping to %g.", value, me->d_out_min_voltage);
me->send_text_message( msg, p.msg_time, vrpn_TEXT_WARNING );
value = me->d_out_min_voltage;
}
if (value > me->d_out_max_voltage) {
char msg[1024];
sprintf( msg, "Error: (handle_request_message): voltage %g is too high. Clamping to %g.", value, me->d_out_max_voltage);
me->send_text_message( msg, p.msg_time, vrpn_TEXT_WARNING );
value = me->d_out_max_voltage;
}
me->o_channel[chan_num] = value;
// Send the new value to the D/A board
#if defined(VRPN_USE_NATIONAL_INSTRUMENTS_MX)
if (!me->setValues()) {
me->send_text_message( "vrpn_National_Instruments_Server::handle_request_message(): Could not set values", p.msg_time, vrpn_TEXT_ERROR );
return -1;
}
#elif defined(VRPN_USE_NATIONAL_INSTRUMENTS)
if (me->d_device_number != -1) {
AO_VWrite(me->d_device_number, (short)(chan_num), value);
}
#endif
return 0;
}
/* static */
int vrpn_National_Instruments_Server::handle_request_channels_message(void* userdata,
vrpn_HANDLERPARAM p)
{
const char* bufptr = p.buffer;
vrpn_int32 num;
vrpn_int32 pad;
vrpn_National_Instruments_Server* me = (vrpn_National_Instruments_Server*)userdata;
vrpn_int32 chan_num;
vrpn_float64 value;
// Read the values from the buffer
vrpn_unbuffer(&bufptr, &num);
vrpn_unbuffer(&bufptr, &pad);
if (num > me->o_num_channel)
{
char msg[1024];
sprintf( msg, "Error: (handle_request_channels_message): channels above %d not active; "
"bad request up to channel %d. Squelching.", me->o_num_channel, num );
me->send_text_message( msg, p.msg_time, vrpn_TEXT_ERROR );
num = me->o_num_channel;
}
if (num < 0)
{
char msg[1024];
sprintf( msg, "Error: (handle_request_channels_message): invalid channel %d. Squelching.", num );
me->send_text_message( msg, p.msg_time, vrpn_TEXT_ERROR );
return 0;
}
for (chan_num = 0; chan_num < num; chan_num++) {
vrpn_unbuffer(&bufptr, &value);
// Make sure the voltage value is within the allowed range.
if (value < me->d_out_min_voltage) {
char msg[1024];
sprintf( msg, "Error: (handle_request_messages): voltage %g is too low. Clamping to %g.", value, me->d_out_min_voltage);
me->send_text_message( msg, p.msg_time, vrpn_TEXT_WARNING );
value = me->d_out_min_voltage;
}
if (value > me->d_out_max_voltage) {
char msg[1024];
sprintf( msg, "Error: (handle_request_messages): voltage %g is too high. Clamping to %g.", value, me->d_out_max_voltage);
me->send_text_message( msg, p.msg_time, vrpn_TEXT_WARNING );
value = me->d_out_max_voltage;
}
me->o_channel[chan_num] = value;
// Send the new value to the D/A board
#ifdef VRPN_USE_NATIONAL_INSTRUMENTS
if (me->d_device_number != -1) {
AO_VWrite(me->d_device_number, (short)(chan_num), value);
}
#endif
}
#if defined(VRPN_USE_NATIONAL_INSTRUMENTS_MX)
if (!me->setValues()) {
me->send_text_message( "vrpn_National_Instruments_Server::handle_request_channels_message(): Could not set values", p.msg_time, vrpn_TEXT_ERROR );
return -1;
}
#endif
return 0;
}
#if defined(VRPN_USE_NATIONAL_INSTRUMENTS_MX)
bool vrpn_National_Instruments_Server::setValues() {
// Send all current values to the board, including the
// changed one.
float64 outbuffer[vrpn_CHANNEL_MAX];
int i;
for (i = 0; i < vrpn_Analog_Output::o_num_channel ; i++) {
outbuffer[i] = vrpn_Analog_Output::o_channel[i];
}
int32 error;
error = DAQmxWriteAnalogF64(d_analog_out_task_handle, 1, true, 1.0,
DAQmx_Val_GroupByChannel, outbuffer, NULL, NULL);
if (error) {
reportError(error);
return false;
}
/*
printf("Debug: Setting %d channels:", o_num_channel);
for (i = 0; i < o_num_channel; i++) {
printf(" %lg", outbuffer[i]);
}
printf("\n");
*/
return true;
}
#endif
/* static */
int VRPN_CALLBACK vrpn_National_Instruments_Server::handle_got_connection( void* userdata, vrpn_HANDLERPARAM )
{
vrpn_National_Instruments_Server* me = (vrpn_National_Instruments_Server*) userdata;
if( me->report_num_channels( ) == false ) {
fprintf( stderr, "Error: failed sending active channels to client.\n" );
}
return 0;
}
bool vrpn_National_Instruments_Server::report_num_channels( vrpn_uint32 class_of_service )
{
char msgbuf[ sizeof( vrpn_int32) ];
vrpn_int32 len = sizeof( vrpn_int32 );;
encode_num_channels_to( msgbuf, o_num_channel );
vrpn_gettimeofday( &o_timestamp, NULL );
if( d_connection &&
d_connection->pack_message( len, o_timestamp, report_num_channels_m_id,
d_sender_id, msgbuf, class_of_service ) )
{
fprintf(stderr, "vrpn_Analog_Output_Server_NI (report_num_channels): cannot write message: tossing\n");
return false;
}
return true;
}
vrpn_int32 vrpn_National_Instruments_Server::encode_num_channels_to( char* buf, vrpn_int32 num )
{
// Message includes: int32 number of active channels
int buflen = sizeof(vrpn_int32);
vrpn_buffer(&buf, &buflen, num);
return sizeof(vrpn_int32);
}
vrpn_Analog_Output_Server_NI::vrpn_Analog_Output_Server_NI(const char* name, vrpn_Connection * c,
const char *boardName,
vrpn_int16 numChannels, bool bipolar,
double minVoltage, double maxVoltage) :
vrpn_Analog_Output(name, c),
NI_device_number(-1),
min_voltage(minVoltage),
max_voltage(maxVoltage),
NI_num_channels(numChannels)
{
#ifdef VRPN_USE_NATIONAL_INSTRUMENTS
short i;
short update_mode = 0; //< Mode 0 is immediate
short ref_source = 0; //< Reference source, 0 = internal, 1 = external
double ref_voltage = 0.0;
// Set the polarity
if (bipolar) {
polarity = 0;
} else {
polarity = 1;
}
// Open the D/A board and set the parameters for each channel. Set the voltage for each
// channel to the minimum.
NI_device_number = NIUtil::findDevice(boardName);
if (NI_device_number == -1) {
fprintf(stderr, "vrpn_Analog_Output_Server_NI: Error opening the D/A board %s\n", boardName);
return;
}
for (i = 0; i < NI_num_channels; i++) {
AO_Configure(NI_device_number, i, polarity, ref_source, ref_voltage,
update_mode);
/*
fprintf(stderr,"Configuring channel %d, polarity: %d, reference source: %d, reference_voltage: %lg, update_mode: %d\n",
i, polarity, ref_source, ref_voltage, update_mode);
*/
AO_VWrite(NI_device_number, i, min_voltage);
}
setNumChannels( numChannels );
// Check if we have a connection
if (d_connection == NULL) {
fprintf(stderr, "vrpn_Analog_Output_Server_NI: Can't get connection!\n");
}
// Register a handler for the request channel change message
if (register_autodeleted_handler(request_m_id,
handle_request_message, this, d_sender_id)) {
fprintf(stderr,"vrpn_Analog_Output_Server_NI: can't register change channel request handler\n");
d_connection = NULL;
}
// Register a handler for the request channels change message
if (register_autodeleted_handler(request_channels_m_id,
handle_request_channels_message, this, d_sender_id)) {
fprintf(stderr,"vrpn_Analog_Output_Server_NI: can't register change channels request handler\n");
d_connection = NULL;
}
// Register a handler for vrpn_got_connection, so we can tell the
// client how many channels are active
if( register_autodeleted_handler( got_connection_m_id, handle_got_connection, this ) )
{
fprintf( stderr, "vrpn_Analog_Output_Server_NI: can't register new connection handler\n");
d_connection = NULL;
}
#else
fprintf(stderr,"vrpn_Analog_Output_Server_NI: Support for NI not compiled in, edit vrpn_Configure.h and recompile\n");
#endif
}
// virtual
vrpn_Analog_Output_Server_NI::~vrpn_Analog_Output_Server_NI(void) {}
// virtual
void vrpn_Analog_Output_Server_NI::mainloop(void)
{
// Let the server code do its thing (ping/pong messages)
server_mainloop();
}
vrpn_int32 vrpn_Analog_Output_Server_NI::setNumChannels (vrpn_int32 sizeRequested) {
if (sizeRequested < 0) sizeRequested = 0;
if (sizeRequested > vrpn_CHANNEL_MAX) sizeRequested = vrpn_CHANNEL_MAX;
o_num_channel = sizeRequested;
return o_num_channel;
}
/* static */
int VRPN_CALLBACK vrpn_Analog_Output_Server_NI::handle_request_message(void *userdata,
vrpn_HANDLERPARAM p)
{
const char* bufptr = p.buffer;
vrpn_int32 chan_num;
vrpn_int32 pad;
vrpn_float64 value;
vrpn_Analog_Output_Server_NI* me = (vrpn_Analog_Output_Server_NI*)userdata;
// Read the parameters from the buffer
vrpn_unbuffer(&bufptr, &chan_num);
vrpn_unbuffer(&bufptr, &pad);
vrpn_unbuffer(&bufptr, &value);
// Set the appropriate value, if the channel number is in the
// range of the ones we have.
if ( (chan_num < 0) || (chan_num >= me->o_num_channel) ) {
char msg[1024];
sprintf( msg, "Error: (handle_request_message): channel %d is not active. Squelching.", chan_num );
me->send_text_message( msg, p.msg_time, vrpn_TEXT_ERROR );
return 0;
}
// Make sure the voltage value is within the allowed range.
if (value < me->min_voltage) {
char msg[1024];
sprintf( msg, "Error: (handle_request_message): voltage %g is too low. Clamping to %g.", value, me->min_voltage);
me->send_text_message( msg, p.msg_time, vrpn_TEXT_WARNING );
value = me->min_voltage;
}
if (value > me->max_voltage) {
char msg[1024];
sprintf( msg, "Error: (handle_request_message): voltage %g is too high. Clamping to %g.", value, me->max_voltage);
me->send_text_message( msg, p.msg_time, vrpn_TEXT_WARNING );
value = me->max_voltage;
}
me->o_channel[chan_num] = value;
// Send the new value to the D/A board
#ifdef VRPN_USE_NATIONAL_INSTRUMENTS
if (me->NI_device_number != -1) {
AO_VWrite(me->NI_device_number, (short)(chan_num), value);
}
#endif
return 0;
}
/* static */
int vrpn_Analog_Output_Server_NI::handle_request_channels_message(void* userdata,
vrpn_HANDLERPARAM p)
{
const char* bufptr = p.buffer;
vrpn_int32 num;
vrpn_int32 pad;
vrpn_Analog_Output_Server_NI* me = (vrpn_Analog_Output_Server_NI*)userdata;
vrpn_int32 chan_num;
vrpn_float64 value;
// Read the values from the buffer
vrpn_unbuffer(&bufptr, &num);
vrpn_unbuffer(&bufptr, &pad);
if (num > me->o_num_channel)
{
char msg[1024];
sprintf( msg, "Error: (handle_request_channels_message): channels above %d not active; "
"bad request up to channel %d. Squelching.", me->o_num_channel, num );
me->send_text_message( msg, p.msg_time, vrpn_TEXT_ERROR );
num = me->o_num_channel;
}
if (num < 0)
{
char msg[1024];
sprintf( msg, "Error: (handle_request_channels_message): invalid channel %d. Squelching.", num );
me->send_text_message( msg, p.msg_time, vrpn_TEXT_ERROR );
return 0;
}
for (chan_num = 0; chan_num < num; chan_num++) {
vrpn_unbuffer(&bufptr, &value);
// Make sure the voltage value is within the allowed range.
if (value < me->min_voltage) {
char msg[1024];
sprintf( msg, "Error: (handle_request_messages): voltage %g is too low. Clamping to %g.", value, me->min_voltage);
me->send_text_message( msg, p.msg_time, vrpn_TEXT_WARNING );
value = me->min_voltage;
}
if (value > me->max_voltage) {
char msg[1024];
sprintf( msg, "Error: (handle_request_messages): voltage %g is too high. Clamping to %g.", value, me->max_voltage);
me->send_text_message( msg, p.msg_time, vrpn_TEXT_WARNING );
value = me->max_voltage;
}
me->o_channel[chan_num] = value;
// Send the new value to the D/A board
#ifdef VRPN_USE_NATIONAL_INSTRUMENTS
if (me->NI_device_number != -1) {
AO_VWrite(me->NI_device_number, (short)(chan_num), value);
}
#endif
}
return 0;
}
/* static */
int VRPN_CALLBACK vrpn_Analog_Output_Server_NI::handle_got_connection( void* userdata, vrpn_HANDLERPARAM )
{
vrpn_Analog_Output_Server_NI* me = (vrpn_Analog_Output_Server_NI*) userdata;
if( me->report_num_channels( ) == false )
{
fprintf( stderr, "Error: failed sending active channels to client.\n" );
}
return 0;
}
bool vrpn_Analog_Output_Server_NI::report_num_channels( vrpn_uint32 class_of_service )
{
char msgbuf[ sizeof( vrpn_int32) ];
vrpn_int32 len = sizeof( vrpn_int32 );;
encode_num_channels_to( msgbuf, o_num_channel );
vrpn_gettimeofday( &o_timestamp, NULL );
if( d_connection &&
d_connection->pack_message( len, o_timestamp, report_num_channels_m_id,
d_sender_id, msgbuf, class_of_service ) )
{
fprintf(stderr, "vrpn_Analog_Output_Server_NI (report_num_channels): cannot write message: tossing\n");
return false;
}
return true;
}
vrpn_int32 vrpn_Analog_Output_Server_NI::
encode_num_channels_to( char* buf, vrpn_int32 num )
{
// Message includes: int32 number of active channels
int buflen = sizeof(vrpn_int32);
vrpn_buffer(&buf, &buflen, num);
return sizeof(vrpn_int32);
}
// This handles error reporting
#ifdef VRPN_USE_NATIONAL_INSTRUMENTS_MX
void vrpn_National_Instruments_Server::reportError(int32 errnumber, vrpn_bool exitProgram)
{
char errBuff[2048]={'\0'};
if( DAQmxFailed(errnumber) )
{
DAQmxGetExtendedErrorInfo(errBuff,2048);
printf("DAQmx Error: %s\n",errBuff);
if (exitProgram==vrpn_true) {
printf("Exiting...\n") ;
throw(errnumber) ; // this will quit, cause the destructor to be called
} else {
printf("Sleeping...\n") ;
vrpn_SleepMsecs(1000.0*1) ; // so at least the log will slow down so someone can see the error
}
}
} // reportError
#endif