//Gateway routine void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { //Read input arguments char outputFormat[10]; char outputVarName[MAXVARNAMESIZE]; int outputVarSampsPerChan; double timeout; int numSampsPerChan; bool outputData; //Indicates whether to return an outputData argument mxClassID outputDataClass; uInt32 bufSize; bool writeDigitalLines; uInt32 bytesPerChan=0; TaskHandle taskID, *taskIDPtr; int32 status; //Get TaskHandle taskIDPtr = (TaskHandle*)mxGetData(mxGetProperty(prhs[0],0, "taskID")); taskID = *taskIDPtr; //Determine if this is a buffered read operation status = DAQmxGetBufInputBufSize(taskID, &bufSize); if (status) handleDAQmxError(status, "DAQmxGetBufInputBufSize"); //Handle input arguments if ((nrhs < 2) || mxIsEmpty(prhs[1]) || mxIsInf(mxGetScalar(prhs[1]))) { if (bufSize==0) numSampsPerChan = 1; else numSampsPerChan = DAQmx_Val_Auto; } else numSampsPerChan = (int) mxGetScalar(prhs[1]); if ((nrhs < 3) || mxIsEmpty(prhs[2])) { //Automatic determination of read type bool isLineBased = (bool) mxGetScalar(mxGetProperty(prhs[0],0,"isLineBasedDigital")); if ((bufSize==0) && isLineBased) //This is a non-buffered, line-based Task: return data as a double array outputDataClass = mxDOUBLE_CLASS; else { status = DAQmxGetReadDigitalLinesBytesPerChan(taskID,&bytesPerChan); //This actually returns the number of bytes required to represent one sample of Channel data if (status) handleDAQmxError(status, "DAQmxGetReadDigitalLinesBytesPerChan"); if (bytesPerChan <= 8) outputDataClass = mxUINT8_CLASS; else if (bytesPerChan <= 16) outputDataClass = mxUINT16_CLASS; else if (bytesPerChan <= 32) outputDataClass = mxUINT32_CLASS; else mexErrMsgTxt("It is not currently possible to read integer values from Task with greater than 32 lines per sample value"); } } else { mxGetString(prhs[2], outputFormat, 10); if (_strcmpi(outputFormat,"uint8")) outputDataClass = mxUINT8_CLASS; else if (_strcmpi(outputFormat,"uint16")) outputDataClass = mxUINT16_CLASS; else if (_strcmpi(outputFormat,"uint32")) outputDataClass = mxUINT32_CLASS; else if (_strcmpi(outputFormat,"double")) outputDataClass = mxDOUBLE_CLASS; else if (_strcmpi(outputFormat,"logical")) outputDataClass = mxLOGICAL_CLASS; else mexErrMsgTxt("The specified 'outputFormat' value (case-sensitive) is not recognized."); } if ((outputDataClass == mxDOUBLE_CLASS) || (outputDataClass == mxLOGICAL_CLASS)) { writeDigitalLines = true; if (bytesPerChan == 0) { status = DAQmxGetReadDigitalLinesBytesPerChan(taskID,&bytesPerChan); //This actually returns the number of bytes required to represent one sample of Channel data if (status) handleDAQmxError(status, "DAQmxGetReadDigitalLinesBytesPerChan"); } } else writeDigitalLines = false; if ((nrhs < 4) || mxIsEmpty(prhs[3]) || mxIsInf(mxGetScalar(prhs[3]))) timeout = DAQmx_Val_WaitInfinitely; else timeout = mxGetScalar(prhs[3]); if ((nrhs < 5) || mxIsEmpty(prhs[4])) //OutputVarSizeOrName argument { outputData = true; outputVarSampsPerChan = numSampsPerChan; //If value is DAQmx_Val_Auto, then the # of samples available will be queried before allocting array } else { outputData = mxIsNumeric(prhs[4]); if (outputData) { if (nlhs < 2) mexErrMsgTxt("There must be two output arguments specified if a preallocated MATLAB variable is not specified"); outputVarSampsPerChan = (int) mxGetScalar(prhs[4]); } else mxGetString(prhs[4], outputVarName, MAXVARNAMESIZE); } //Determin # of output channels uInt32 numChannels; DAQmxGetReadNumChans(taskID, &numChannels); //Reflects number of channels in Task, or the number of channels specified by 'ReadChannelsToRead' property //Determine output buffer/size (creating if needed) mxArray *outputDataBuf, *outputDataBufTrue; void *outputDataPtr; //float64 *outputDataPtr; if (outputData) { mwSize numRows; if (outputVarSampsPerChan == DAQmx_Val_Auto) { status = DAQmxGetReadAvailSampPerChan(taskID, (uInt32 *)&outputVarSampsPerChan); if (status) { handleDAQmxError(status, "DAQmxGetReadAvailSampPerChan"); return; } } if (writeDigitalLines) numRows = (mwSize) (outputVarSampsPerChan * bytesPerChan); else numRows = (mwSize) outputVarSampsPerChan; if (outputDataClass == mxDOUBLE_CLASS) { outputDataBuf = mxCreateNumericMatrix(numRows,numChannels,mxUINT8_CLASS,mxREAL); outputDataBufTrue = mxCreateDoubleMatrix(numRows,numChannels,mxREAL); } else outputDataBuf = mxCreateNumericMatrix(numRows,numChannels,outputDataClass,mxREAL); } else //I don't believe this is working { outputDataBuf = mexGetVariable("caller", outputVarName); outputVarSampsPerChan = mxGetM(outputDataBuf); //TODO: Add check to ensure WS variable is of correct class } outputDataPtr = mxGetData(outputDataBuf); //Read data int32 numSampsRead; int32 numBytesPerSamp; switch (outputDataClass) { case mxUINT8_CLASS: status = DAQmxReadDigitalU8(taskID, numSampsPerChan, timeout, fillMode, (uInt8*) outputDataPtr, outputVarSampsPerChan * numChannels, &numSampsRead, NULL); break; case mxUINT16_CLASS: status = DAQmxReadDigitalU16(taskID, numSampsPerChan, timeout, fillMode, (uInt16*) outputDataPtr, outputVarSampsPerChan * numChannels, &numSampsRead, NULL); break; case mxUINT32_CLASS: status = DAQmxReadDigitalU32(taskID, numSampsPerChan, timeout, fillMode, (uInt32*) outputDataPtr, outputVarSampsPerChan * numChannels, &numSampsRead, NULL); break; case mxLOGICAL_CLASS: case mxDOUBLE_CLASS: status = DAQmxReadDigitalLines(taskID, numSampsPerChan, timeout, fillMode, (uInt8*) outputDataPtr, outputVarSampsPerChan * numChannels * bytesPerChan, &numSampsRead, &numBytesPerSamp, NULL); break; default: mexErrMsgTxt("There must be two output arguments specified if a preallocated MATLAB variable is not specified"); } //Return output data if (!status) { //mexPrintf("Successfully read %d samples of data\n", numSampsRead); if (outputData) { if (nlhs > 0) { if (outputDataClass == mxDOUBLE_CLASS) { //Convert logical data to double type double *outputDataTruePtr = mxGetPr(outputDataBufTrue); for (size_t i=0;i < mxGetNumberOfElements(outputDataBuf);i++) *(outputDataTruePtr+i) = (double) *((uInt8 *)outputDataPtr+i); mxDestroyArray(outputDataBuf); plhs[0] = outputDataBufTrue; } else plhs[0] = outputDataBuf; } else mxDestroyArray(outputDataBuf); //If you don't read out, all the reading was done for naught } else //I don't believe this is working { mexErrMsgTxt("invalid branch"); mexPutVariable("caller", outputVarName, outputDataBuf); if (nlhs > 0) //Return empty value for output data plhs[0] = mxCreateDoubleMatrix(0,0,mxREAL); } if (nlhs > 1) //Return number of samples actually read { double *sampsReadOutput; plhs[1] = mxCreateDoubleScalar(0); sampsReadOutput = mxGetPr(plhs[1]); *sampsReadOutput = (double)numSampsRead; } } else //Read failed handleDAQmxError(status, mexFunctionName()); }
// [outputData, sampsPerChanRead] = readAnalogData(task, numSampsPerChan, outputFormat, timeout, outputVarSizeOrName) void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { //Read input arguments // Get the task handle mxArray *mxTaskID = mxGetProperty(prhs[0],0,"taskID"); mxClassID clsID = mxGetClassID(mxTaskID); localAssert(clsID==TASKHANDLE_MXCLASS); TaskHandle *taskIDPtr = (TaskHandle*)mxGetData(mxTaskID); TaskHandle taskID = *taskIDPtr; //Determine if this is a buffered read operation uInt32 bufSize = 0; int32 status = DAQmxGetBufInputBufSize(taskID,&bufSize); if (status) { handleDAQmxError(status,"DAQmxGetBufInputBufSize"); } // Handle input arguments int32 numSampsPerChan = 0; // this does take negative vals in the case of DAQmx_Val_Auto if ((nrhs < 2) || mxIsEmpty(prhs[1]) || mxIsInf(mxGetScalar(prhs[1]))) { if (bufSize==0) numSampsPerChan = 1; else numSampsPerChan = DAQmx_Val_Auto; } else { numSampsPerChan = (int) mxGetScalar(prhs[1]); } char outputFormat[10]; if ((nrhs < 3) || mxIsEmpty(prhs[2])) strcpy_s(outputFormat,"scaled"); else mxGetString(prhs[2], outputFormat, 10); double timeout; if ((nrhs < 4) || mxIsEmpty(prhs[3]) || mxIsInf(mxGetScalar(prhs[3]))) timeout = DAQmx_Val_WaitInfinitely; else timeout = mxGetScalar(prhs[3]); bool outputData; //Indicates whether to return an outputData argument int outputVarSampsPerChan = 0; // this CAN take negative values in case of DAQmx_Val_Auto char outputVarName[MAXVARNAMESIZE]; if ((nrhs < 5) || mxIsEmpty(prhs[4])) { outputData = true; outputVarSampsPerChan = numSampsPerChan; //If value is DAQmx_Val_Auto, then the # of samples available will be queried before allocting array } else { outputData = mxIsNumeric(prhs[4]); if (outputData) { if (nlhs < 2) { mexErrMsgTxt("There must be two output arguments specified if a preallocated MATLAB variable is not specified"); } outputVarSampsPerChan = (int) mxGetScalar(prhs[4]); } else { mxGetString(prhs[4],outputVarName,MAXVARNAMESIZE); } } //Determine output data type mxClassID outputDataClass; mxArray *mxRawDataArrayAI = mxGetProperty(prhs[0],0,"rawDataArrayAI"); //Stored in MCOS Task object as an empty array of the desired class! mxClassID rawDataClass = mxGetClassID(mxRawDataArrayAI); char errorMessage[30]; if (!_strcmpi(outputFormat,"scaled")) outputDataClass = mxDOUBLE_CLASS; else if (!_strcmpi(outputFormat,"native")) outputDataClass = rawDataClass; else { sprintf_s(errorMessage,"Unrecognized output format: %s\n",outputFormat); mexErrMsgTxt(errorMessage); } //Determine # of output channels uInt32 numChannels; DAQmxGetReadNumChans(taskID,&numChannels); //Reflects number of channels in Task, or the number of channels specified by 'ReadChannelsToRead' property //Determine output buffer/size (creating if needed) mxArray *mxOutputDataBuf = NULL; if (outputData) { if (outputVarSampsPerChan == DAQmx_Val_Auto) { uInt32 buf = 0; status = DAQmxGetReadAvailSampPerChan(taskID,&buf); if (status) { handleDAQmxError(status, mexFunctionName()); } outputVarSampsPerChan = buf; } //localAssert(outputVarSampsPerChan >= 0); localAssert(outputVarSampsPerChan > 0); mxOutputDataBuf = mxCreateNumericMatrix(outputVarSampsPerChan,numChannels,outputDataClass,mxREAL); } else { localAssert(false); ////I don't believe this is working //mxOutputDataBuf = mexGetVariable("caller", outputVarName); //outputVarSampsPerChan = mxGetM(mxOutputDataBuf); ////TODO: Add check to ensure WS variable is of correct class } void* outputDataPtr = mxGetData(mxOutputDataBuf); localAssert(outputDataPtr!=NULL); uInt32 arraySizeInSamps = outputVarSampsPerChan * numChannels; localAssert(mxGetNumberOfElements(mxOutputDataBuf)==(size_t)arraySizeInSamps); int32 numSampsPerChanRead; if (outputDataClass == mxDOUBLE_CLASS) //'scaled' // float64 should be double status = DAQmxReadAnalogF64(taskID,numSampsPerChan,timeout,fillMode, (float64*) outputDataPtr, arraySizeInSamps, &numSampsPerChanRead, NULL); else { //'raw' switch (outputDataClass) { case mxINT16_CLASS: status = DAQmxReadBinaryI16(taskID, numSampsPerChan, timeout, fillMode, (int16*) outputDataPtr, arraySizeInSamps, &numSampsPerChanRead, NULL); break; case mxINT32_CLASS: status = DAQmxReadBinaryI32(taskID, numSampsPerChan, timeout, fillMode, (int32*) outputDataPtr, arraySizeInSamps, &numSampsPerChanRead, NULL); break; case mxUINT16_CLASS: status = DAQmxReadBinaryU16(taskID, numSampsPerChan, timeout, fillMode, (uInt16*) outputDataPtr, arraySizeInSamps, &numSampsPerChanRead, NULL); break; case mxUINT32_CLASS: status = DAQmxReadBinaryU32(taskID, numSampsPerChan, timeout, fillMode, (uInt32*) outputDataPtr, arraySizeInSamps, &numSampsPerChanRead, NULL); break; } } //Return output data if (!status) { //mexPrintf("Successfully read %d samples of data\n", numSampsRead); if (outputData) { if (nlhs > 0) plhs[0] = mxOutputDataBuf; else mxDestroyArray(mxOutputDataBuf); //If you don't read out, all the reading was done for naught } else { //I don't believe this is working localAssert(false); //mexPutVariable("caller", outputVarName, mxOutputDataBuf); // //if (nlhs >= 0) //Return empty value for output data // plhs[0] = mxCreateDoubleMatrix(0,0,mxREAL); } if (nlhs>1) { //Return number of samples actually read plhs[1] = mxCreateDoubleScalar(0.0); double *sampsReadOutput = mxGetPr(plhs[1]); *sampsReadOutput = (double)numSampsPerChanRead; } } else { //Read failed handleDAQmxError(status, mexFunctionName()); } }