02-23-2011 02:20 PM
I now have a small test program, that contains only the NI data collection routines, without any of the rest of my app.
I have attached the code below. When I run this on my new machine, it fails around 40% of the time, in DAQmxReadAnalogF64, with error 200010.
(When I try to clean up after this, I then get error -200088 when I call StopTask on the handle.)
Am I doing something wrong here?
First the error handling code...
// ni_test - Test call of NIDAQ functions.
#include <stdio.h>
#include "../NationalInstruments/NIDAQmx.h"
class Nidaq_Exception
{
public:
int32 error_code;
Nidaq_Exception (int32 _error_code)
{
error_code = _error_code;
}
};
void CheckNidaqError (int32 error_code)
// Check the NIDAQmx return code - If non zero, print messages and raise an exception.
{
if (error_code != 0)
{
// get error message
int msg_len = DAQmxGetErrorString (error_code, NULL, 0);
if (msg_len > 0)
{
char* msg = new char [msg_len];
int result = DAQmxGetErrorString (error_code, msg, msg_len);
printf ("NIDAQ error %d : %s\n", error_code, msg);
delete[] msg;
}
// get extended error message
int extended_msg_len = DAQmxGetExtendedErrorInfo (NULL, 0);
if (extended_msg_len > 0)
{
char* extended_msg = new char [extended_msg_len];
int extended_result = DAQmxGetExtendedErrorInfo (extended_msg, extended_msg_len);
printf ("Extended error message:\n%s\n", extended_msg);
delete[] extended_msg;
}
// if error, raise exception.
if (error_code < 0)
{
Nidaq_Exception exc (error_code);
throw exc;
}
}
}
void CleanupTask (TaskHandle* phandle)
// Clean up a partially-started task, in the event of an error.
{
int32 result;
// stop task
result = DAQmxStopTask (*phandle);
if (result != 0)
{
printf ("Failure in DAQmxStopTask\n");
CheckNidaqError (result);
}
// destroy task
result = DAQmxClearTask (*phandle);
if (result != 0)
{
printf ("Failure in DAQmxClearTask\n");
CheckNidaqError (result);
}
*phandle = 0; // clear handle value [not sure if this is the correct value]
}
02-23-2011 02:21 PM
Now the A/D collection code...
bool Test_AD_Collect ()
// Collect data, return true if successful.
{
const char* channels = "Dev1/ai1";
double data [20000];
int data_size = sizeof (data) / sizeof (data [0]);
double min_range = -10.0;
double max_range = +10.0;
int num_samps_per_channel = 20000;
double samp_freq_per_channel = 200000.0;
double timeout_sec = 1.1; // enough
//double timeout_sec = 0.0; // force timeout error
bool rtn = false;
try
{
int32 result;
TaskHandle handle;
result = DAQmxCreateTask (NULL, &handle);
if (result != 0)
{
printf ("Failure in DAQmxCreateTask\n");
CleanupTask (&handle);
CheckNidaqError (result);
}
// create channel for reading voltage
result = DAQmxCreateAIVoltageChan
(handle,
channels,
NULL,
DAQmx_Val_Cfg_Default,
min_range,
max_range,
DAQmx_Val_Volts, // units
NULL);
if (result != 0)
{
printf ("Failure in DAQmxCreateAIVoltageChan\n");
CleanupTask (&handle);
CheckNidaqError (result);
}
// get channel count
uInt32 nidaq_num_channels;
result = DAQmxGetTaskNumChans (handle, &nidaq_num_channels);
if (result != 0)
{
printf ("Failure in DAQmxGetTaskNumChans\n");
CleanupTask (&handle);
CheckNidaqError (result);
}
// configure sample clock - frequency is based on the number of channels in task
result = DAQmxCfgSampClkTiming
(handle,
NULL, // "OnboardClock" is ok too
samp_freq_per_channel,
DAQmx_Val_Rising, // collect on the rising edge of the clock
DAQmx_Val_FiniteSamps,
num_samps_per_channel);
if (result != 0)
{
printf ("Failure in DAQmxCfgSampClkTiming\n");
CleanupTask (&handle);
CheckNidaqError (result);
}
// read data
int32 samps_per_chan_read;
result = DAQmxReadAnalogF64
(handle,
num_samps_per_channel,
timeout_sec,
DAQmx_Val_GroupByScanNumber, // interleaved
data,
data_size,
&samps_per_chan_read,
NULL);
if (result != 0)
{
printf ("Failure in DAQmxReadAnalogF64\n");
CleanupTask (&handle);
CheckNidaqError (result);
}
// clean up
CleanupTask (&handle);
// success
rtn = true;
}
catch (Nidaq_Exception)
{
// failed
rtn = false;
}
return rtn;
}
void NiTest (int count)
{
int num_ok = 0;
int num_bad = 0;
for (int i=0; i < count; i++)
{
bool ok = Test_AD_Collect ();
if (ok)
{
num_ok += 1;
}
else
{
num_bad += 1;
}
}
printf ("A/D Test: Did %d collections, %d ok, %d errors.\n", count, num_ok, num_bad);
}
int main (int argc, char* argv[])
{
//NiTest (50);
NiTest (500);
return 0;
}
02-23-2011 06:00 PM
Ok, I have found my problem 🙂
First, I was not calling StartTask before I started to read data. I had somehow thought that was optional, but omitting it seems to make the 200010 warning much more likely, at least on this system.
Second, I was not handling errors properly. First, I somewhat treated the 200010 warning as an error, trying to abort and clean up the task when this happened.
Then, (much worse), I then tried to clean up the task twice. This invalid second cleanup generated an error code, -200080 I think, with the result that my program treated the results as an error.
With these fixes, it seems that everything is working fine now.