06-05-2015 02:30 PM
The code shown below is a callback for 1 to 3 analog input tasks. Why would is throw a random error of "Array argument too small" on the second task's DAQmxReadAnalogF64 call? Is this the best way to handle continous data from multiple tasks? This is the way I do it in VB.NET/Measurement Studio.
int32 CVICALLBACK AIDataReady(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData) { int32 error=0; char errBuff[2048]={'\0'}; int numRead; // Read DAQmx data if (taskHandle == ai0TaskHandle) DAQmxErrChk (DAQmxReadAnalogF64(taskHandle,nSamples,10.0,DAQmx_Val_GroupByChannel,aiTask0RawData,nSamples*numTask0Channels,&numRead,NULL)); else if (taskHandle == ai1TaskHandle) DAQmxErrChk (DAQmxReadAnalogF64(taskHandle,nSamples,10.0,DAQmx_Val_GroupByChannel,aiTask1RawData,nSamples*numTask1Channels,&numRead,NULL)); else if (taskHandle == ai2TaskHandle) DAQmxErrChk (DAQmxReadAnalogF64(taskHandle,nSamples,10.0,DAQmx_Val_GroupByChannel,aiTask2RawData,nSamples*numTask2Channels,&numRead,NULL)); // Call function calculate engineering units from raw voltages DAQCalculateAverages(); Error: if( DAQmxFailed(error) ) { DAQmxGetExtendedErrorInfo(errBuff,2048); /*********************************************/ /*/ DAQmx Stop Code /*********************************************/ DAQmxStopTask(taskHandle); DAQmxClearTask(taskHandle); ai0TaskHandle = 0; if(aiRawData) { free(aiRawData); aiRawData = NULL; } } return 0; }
06-08-2015 05:17 PM
Hi Michael,
What have you defined as aiTask1RawData? The "Array argument too small" error code should specify the number of array elements required.
06-09-2015 07:51 AM
They are global variables. The error is completely random. It can work for 5 minutes, or last night it ran all the way through with no issues. It is always on the second task. The error box does tell me how many bytes it is expecting and how many it gets. Why would it work most of the time and then fail to return the proper number of bytes? The chassis is an older 9178 cDAQ chassis (white, not grey).
static float64 *aiTask0RawData=NULL;
static float64 *aiTask1RawData=NULL;
static float64 *aiTask2RawData=NULL;
06-09-2015 03:40 PM
Here is the error it throws. The number of bytes received is random.
06-10-2015 06:28 PM
Michael,
Have you tried reallocating memory to aiTask1RawData before reading data to ensure that there are at least nSamples*numTask1Channels elements in the buffer?
06-11-2015 10:55 AM
Does this error mean that the array is too small or that the amount of data going into it is too little?
If the array is too small, how it is changing sizes at run time when I set it up to be as large as it needs to be at the beginning of execution and leave it alone the rest of the time?
06-11-2015 03:52 PM
What do you set the array length as?
Is it fixed, or dynamic?
The behaviour you describe suggests a race condition. Is it possible for AIDataReady to be called for ai1TaskHandle when AIDataReady is actually executing ai0TaskHandle already?
06-11-2015 04:22 PM - edited 06-11-2015 04:23 PM
This is how the array is built. lastTask is just a task count. If there is one task, it will be and the loop will iterate only once.
for (ctrChannels = 0; ctrChannels < lastTask; ctrChannels++) { switch (ctrChannels) { case 0: TempTaskHandle = ai0TaskHandle; numTempTaskChannels = numTask0Channels; aiTask0RawData=malloc(DAQNumSamples*numTask0Channels*sizeof(float64)); break; case 1: TempTaskHandle = ai1TaskHandle; numTempTaskChannels = numTask1Channels; aiTask1RawData=malloc(DAQNumSamples*numTask1Channels*sizeof(float64)); break; case 2: TempTaskHandle = ai2TaskHandle; numTempTaskChannels = numTask2Channels; aiTask0RawData=malloc(DAQNumSamples*numTask2Channels*sizeof(float64)); break; default: break; } DAQmxErrChk (DAQmxCfgSampClkTiming(TempTaskHandle,"",1000,DAQmx_Val_Rising,DAQmx_Val_ContSamps,DAQNumSamples)); //DAQmxErrChk (DAQmxSetChanAttribute(ai0TaskHandle,"",DAQmx_AI_Lowpass_Enable,1)); //DAQmxErrChk (DAQmxSetChanAttribute(ai0TaskHandle,"",DAQmx_AI_Lowpass_CutoffFreq,cutoffFreq)); //DAQmxErrChk (DAQmxGetChanAttribute(ai0TaskHandle,"",DAQmx_AI_Lowpass_CutoffFreq,&cutoffFreq)); DAQmxErrChk (DAQmxGetTaskAttribute(TempTaskHandle,DAQmx_Task_NumChans,&numTempTaskChannels)); DAQmxErrChk (DAQmxRegisterEveryNSamplesEvent(TempTaskHandle,DAQmx_Val_Acquired_Into_Buffer,DAQNumSamples,0,AIDataReady,NULL)); DAQmxErrChk (DAQmxRegisterDoneEvent(TempTaskHandle,0,AIDataStop,NULL)); /*********************************************/ // DAQmx AI Start Code /*********************************************/ DAQmxErrChk (DAQmxStartTask(TempTaskHandle)); }
This is how the data is read to generate an average value for each channel (100 readings @ 1 kHz). It is possible that the pointer is not being reset to the beginning of the array (last line of this code), but I don't understand the random nature.
if (numTask1Channels) { for (indexChannel = numTask0Channels; indexChannel < (numTask0Channels + numTask1Channels);indexChannel++) { Sum = 0; for (indexSample = 0; indexSample < DAQNumSamples; indexSample++) { Sum += *aiTask1RawData++; } // Average value -> Raw data DAQAIRawData[indexChannel] = Sum / DAQNumSamples; // Raw data -> Engineering units if (!IsInfinity(DAQAIRawData[indexChannel])) DAQAIEngrUnits[indexChannel] = DAQAIChannels[indexChannel]->Quartic * pow(DAQAIRawData[indexChannel], 4) + DAQAIChannels[indexChannel]->Cubic * pow(DAQAIRawData[indexChannel], 3) + DAQAIChannels[indexChannel]->Quadratic * pow(DAQAIRawData[indexChannel], 2) + DAQAIChannels[indexChannel]->Linear * DAQAIRawData[indexChannel] + DAQAIChannels[indexChannel]->Offset; else DAQAIEngrUnits[indexChannel] = DAQAIRawData[indexChannel]; } // Reset aiTask1RawData pointer back to its original location aiTask1RawData -= DAQNumSamples * numTask1Channels; }
I am using the task handle to select which array to work with. The call back should send the proper task handle.
06-13-2015 06:05 AM
Is there an obvious error in this code:
switch (ctrChannels) { case 0: TempTaskHandle = ai0TaskHandle; numTempTaskChannels = numTask0Channels; aiTask0RawData=malloc(DAQNumSamples*numTask0Channels*sizeof(float64)); break; case 1: TempTaskHandle = ai1TaskHandle; numTempTaskChannels = numTask1Channels; aiTask1RawData=malloc(DAQNumSamples*numTask1Channe ls*sizeof(float64)); break; case 2: TempTaskHandle = ai2TaskHandle; numTempTaskChannels = numTask2Channels; aiTask0RawData=malloc(DAQNumSamples*numTask2Channe ls*sizeof(float64)); break; default: break; }
In case 2, shouldn't aiTask0RawData be aiTask2RawData ?
But it does seem to me that the DAQmxEveryNSamplesEvent, say for ai1Task can happen at the instant when AIDataReady is processing the DAQmxEveryNSamplesEvent for ai0Task. I do not know whether in this instance LabWindows queues the callbacks, or trys a reentrent call to AIDataReady.
06-15-2015 07:58 AM
Good catch. I don't have three tasks, so I didn't catch that myself. I'll fix it now.
Should I have a separate callback function for each task?