//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()); }
//Gateway routine //sampsPerChanWritten = writeAnalogData(task, writeData, timeout, autoStart, numSampsPerChan) void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { //General vars char errMsg[512]; //Read input arguments float64 timeout; int numSampsPerChan; bool32 autoStart; TaskHandle taskID, *taskIDPtr; //Get TaskHandle taskIDPtr = (TaskHandle*)mxGetData(mxGetProperty(prhs[0],0, "taskID")); taskID = *taskIDPtr; if ((nrhs < 3) || mxIsEmpty(prhs[2])) timeout = 10.0; else { timeout = (float64) mxGetScalar(prhs[2]); if (mxIsInf(timeout)) timeout = DAQmx_Val_WaitInfinitely; } if ((nrhs < 4) || mxIsEmpty(prhs[3])) { int32 sampTimingType = 0; int32 status = DAQmxGetSampTimingType(taskID,&sampTimingType); if (status!=0) { mexErrMsgTxt("Failed to get sample timing type from DAQmx."); } autoStart = (sampTimingType==DAQmx_Val_OnDemand); } else autoStart = (bool32) mxGetScalar(prhs[3]); size_t numRows = mxGetM(prhs[1]); if ((nrhs < 5) || mxIsEmpty(prhs[4])) numSampsPerChan = numRows; else numSampsPerChan = (int) mxGetScalar(prhs[4]); //Verify correct input length //Write data int32 sampsWritten; int32 status; switch (mxGetClassID(prhs[1])) { case mxUINT16_CLASS: status = DAQmxWriteBinaryU16(taskID, numSampsPerChan, autoStart, timeout, dataLayout, (uInt16*) mxGetData(prhs[1]), &sampsWritten, NULL); break; case mxINT16_CLASS: status = DAQmxWriteBinaryI16(taskID, numSampsPerChan, autoStart, timeout, dataLayout, (int16*) mxGetData(prhs[1]), &sampsWritten, NULL); break; case mxDOUBLE_CLASS: status = DAQmxWriteAnalogF64(taskID, numSampsPerChan, autoStart, timeout, dataLayout, (float64*) mxGetData(prhs[1]), &sampsWritten, NULL); break; default: sprintf_s(errMsg,"Class of supplied writeData argument (%s) is not valid", mxGetClassName(prhs[1])); mexErrMsgTxt(errMsg); } //Handle output arguments and errors if (!status) { if (nlhs > 0) { plhs[0] = mxCreateDoubleScalar(0); double *sampsPerChanWritten = mxGetPr(plhs[0]); } //mexPrintf("Successfully wrote %d samples of data\n", sampsWritten); } else //Write failed handleDAQmxError(status, mexFunctionName()); }
//Gateway routine void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { //General vars char errMsg[512]; //Read input arguments float64 timeout; bool writeDigitalLines; uInt32 bytesPerChan; int numSampsPerChan; bool32 autoStart; int32 status; TaskHandle taskID, *taskIDPtr; //Get TaskHandle taskIDPtr = (TaskHandle*)mxGetData(mxGetProperty(prhs[0],0, "taskID")); taskID = *taskIDPtr; mxClassID writeDataClassID = mxGetClassID(prhs[1]); if ((writeDataClassID == mxLOGICAL_CLASS) || (writeDataClassID == mxDOUBLE_CLASS)) writeDigitalLines = true; else writeDigitalLines = false; if (writeDigitalLines) { status = DAQmxGetWriteDigitalLinesBytesPerChan(taskID,&bytesPerChan); //This actually returns the number of bytes required to represent one sample of Channel data if (status) handleDAQmxError(status,"DAQmxGetWriteDigitalLinesBytesPerChan"); } if ((nrhs < 3) || mxIsEmpty(prhs[2])) timeout = DAQmx_Val_WaitInfinitely; else { timeout = (float64) mxGetScalar(prhs[2]); if (mxIsInf(timeout) || (timeout < 0)) timeout = DAQmx_Val_WaitInfinitely; } if ((nrhs < 4) || mxIsEmpty(prhs[3])) { if (writeDigitalLines) autoStart = true; else autoStart = false; } else autoStart = (bool32) mxGetScalar(prhs[3]); mwSize numRows = mxGetM(prhs[1]); if ((nrhs < 5) || mxIsEmpty(prhs[4])) if (writeDigitalLines) { numSampsPerChan = numRows / bytesPerChan; } else numSampsPerChan = numRows; else numSampsPerChan = (int) mxGetScalar(prhs[4]); //Verify correct input length //Write data int32 sampsWritten; switch (writeDataClassID) { case mxUINT32_CLASS: status = DAQmxWriteDigitalU32(taskID, numSampsPerChan, autoStart, timeout, dataLayout, (uInt32*) mxGetData(prhs[1]), &sampsWritten, NULL); break; case mxUINT16_CLASS: status = DAQmxWriteDigitalU16(taskID, numSampsPerChan, autoStart, timeout, dataLayout, (uInt16*) mxGetData(prhs[1]), &sampsWritten, NULL); break; case mxUINT8_CLASS: status = DAQmxWriteDigitalU8(taskID, numSampsPerChan, autoStart, timeout, dataLayout, (uInt8*) mxGetData(prhs[1]), &sampsWritten, NULL); break; case mxDOUBLE_CLASS: case mxLOGICAL_CLASS: { if (numRows < (numSampsPerChan * bytesPerChan)) mexErrMsgTxt("Supplied writeData argument must have at least (numSampsPerChan x numBytesPerChannel) rows."); else if (writeDataClassID == mxLOGICAL_CLASS) status = DAQmxWriteDigitalLines(taskID, numSampsPerChan, autoStart, timeout, dataLayout, (uInt8*) mxGetData(prhs[1]), &sampsWritten, NULL); else //mxDOUBLE_CLASS { //Convert DOUBLE data to LOGICAL values double *writeDataRaw = mxGetPr(prhs[1]); mwSize numElements = mxGetNumberOfElements(prhs[1]); uInt8 *writeData = (uInt8 *)mxCalloc(numElements,sizeof(uInt8)); for (unsigned int i=0;i<numElements;i++) { if (writeDataRaw[i] != 0) writeData[i] = 1; } status = DAQmxWriteDigitalLines(taskID, numSampsPerChan, autoStart, timeout, dataLayout, writeData, &sampsWritten, NULL); mxFree(writeData); } } break; default: sprintf_s(errMsg,"Class of supplied writeData argument (%s) is not valid", mxGetClassName(prhs[1])); mexErrMsgTxt(errMsg); } //Handle output arguments if (nlhs > 0) { plhs[0] = mxCreateDoubleScalar(0); double *sampsPerChanWritten = mxGetPr(plhs[0]); if (!status) { //mexPrintf("Successfully wrote %d samples of data\n", sampsWritten); *sampsPerChanWritten = (double)sampsWritten; } else //Write 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()); } }
//Gateway routine void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { //General vars char errMsg[512]; //Read input arguments float64 timeout; //bool dataIsLogicalOrDouble; // For unsigned int data (8, 16, or 32-bit) we call DAQmxWriteDigitalU<whatever>() to // write the data to the buffer. For logical or double data, we call DAQmxWriteDigitalLines(). // For the first, the several channel settings have to be "packed" into a single unsigned int. // For the second, each channel is set individually. // Note that a "channel" in this context is a thing you set up with a single call to the // DAQmxCreateDOChan() function. // That is, a channel can consist of more than one TTL line. // This var is set to true iff the data is logical or double. uInt32 maxLinesPerChannel; int32 numSampsPerChan; // The number of time points to output, aka the number of "scans" bool32 autoStart; int32 status; TaskHandle taskID, *taskIDPtr; //Get TaskHandle taskIDPtr = (TaskHandle*)mxGetData(mxGetProperty(prhs[0],0, "taskID")); taskID = *taskIDPtr; // Get type and dimensions of data array mxClassID writeDataClassID = mxGetClassID(prhs[1]); bool dataIsLogicalOrDouble = ((writeDataClassID == mxLOGICAL_CLASS) || (writeDataClassID == mxDOUBLE_CLASS)) ; mwSize numRows = mxGetM(prhs[1]); mwSize numCols = mxGetN(prhs[1]); // Determine the timeout if ((nrhs < 3) || mxIsEmpty(prhs[2])) timeout = DAQmx_Val_WaitInfinitely; else { timeout = (float64) mxGetScalar(prhs[2]); if (mxIsInf(timeout) || (timeout < 0)) timeout = DAQmx_Val_WaitInfinitely; } // Determine whether to start automatically or not if ((nrhs < 4) || mxIsEmpty(prhs[3])) { int32 sampleTimingType; status = DAQmxGetSampTimingType(taskID, &sampleTimingType) ; if (status) handleDAQmxError(status,"DAQmxSetSampTimingType"); if ( sampleTimingType == DAQmx_Val_OnDemand ) { // The task is using on-demand timing, so we want the // new values to be immediately output. (And trying to call // DAQmxWriteDigitalLines() for an on-demand task, with autoStart set to false, // will error anyway. autoStart = (bool32) true; } else { autoStart = (bool32) false; } } else { autoStart = (bool32) mxGetScalar(prhs[3]); } // Determine the number of scans (time points) to write out if ((nrhs < 5) || mxIsEmpty(prhs[4])) { if (dataIsLogicalOrDouble) { status = DAQmxGetWriteDigitalLinesBytesPerChan(taskID,&maxLinesPerChannel); // maxLinesPerChannel is maximum number of lines per channel. // Each DO "channel" can consist of multiple DO lines. (A channel is the thing created with // a call to DAQmxCreateDOChan().) So this returns the maximum number of lines per channel, // across all the channels in the task. When you call DAQmxWriteDigitalLines(), the data must consist // of (number of scans) x (number of channels) x maxLinesPerChannel uint8 elements. If a particular channel has fewer lines // than the max number, the extra ones are ignored. if (status) handleDAQmxError(status,"DAQmxGetWriteDigitalLinesBytesPerChan"); numSampsPerChan = (int32) (numRows/maxLinesPerChannel); // this will do an implicit floor } else numSampsPerChan = (int32) numRows; } else { numSampsPerChan = (int32) mxGetScalar(prhs[4]); } // Verify that the data contains the right number of columns uInt32 numberOfChannels; status = DAQmxGetTaskNumChans(taskID, &numberOfChannels) ; if (status) handleDAQmxError(status,"DAQmxGetTaskNumChans"); if (numCols != numberOfChannels ) { mexErrMsgTxt("Supplied writeData argument must have as many columns as there are channels in the task."); } // Verify that the data contains enough rows that we won't read off the end of it. // Note that for logical or double data, the different lines for each channel must be stored in the *rows*. // So for each time point, there's a maxLinesPerChannel x nChannels submatrix for that time point. int numberOfRowsNeededPerScan = (dataIsLogicalOrDouble ? maxLinesPerChannel : 1) ; int minNumberOfRowsNeeded = numberOfRowsNeededPerScan * numSampsPerChan ; if (numRows < minNumberOfRowsNeeded ) { mexErrMsgTxt("Supplied writeData argument does not have enough rows."); } //Write data int32 scansWritten; switch (writeDataClassID) { case mxUINT32_CLASS: status = DAQmxWriteDigitalU32(taskID, numSampsPerChan, autoStart, timeout, dataLayout, (uInt32*) mxGetData(prhs[1]), &scansWritten, NULL); break; case mxUINT16_CLASS: status = DAQmxWriteDigitalU16(taskID, numSampsPerChan, autoStart, timeout, dataLayout, (uInt16*) mxGetData(prhs[1]), &scansWritten, NULL); break; case mxUINT8_CLASS: status = DAQmxWriteDigitalU8(taskID, numSampsPerChan, autoStart, timeout, dataLayout, (uInt8*) mxGetData(prhs[1]), &scansWritten, NULL); break; case mxLOGICAL_CLASS: status = DAQmxWriteDigitalLines(taskID, numSampsPerChan, autoStart, timeout, dataLayout, (uInt8*) mxGetData(prhs[1]), &scansWritten, NULL); break; case mxDOUBLE_CLASS: { //Convert DOUBLE data to LOGICAL values double *writeDataRaw = mxGetPr(prhs[1]); mwSize numElements = mxGetNumberOfElements(prhs[1]); uInt8 *writeData = (uInt8 *)mxCalloc(numElements,sizeof(uInt8)); for (unsigned int i=0;i<numElements;i++) { if (writeDataRaw[i] != 0) writeData[i] = 1; } status = DAQmxWriteDigitalLines(taskID, numSampsPerChan, autoStart, timeout, dataLayout, writeData, &scansWritten, NULL); mxFree(writeData); } break; default: sprintf_s(errMsg,"Class of supplied writeData argument (%s) is not valid", mxGetClassName(prhs[1])); mexErrMsgTxt(errMsg); } // If an error occured at some point during writing, deal with that if (status) handleDAQmxError(status, mexFunctionName()); // Handle output arguments, if needed if (nlhs > 0) { plhs[0] = mxCreateDoubleScalar(0); double * sampsPerChanWritten = mxGetPr(plhs[0]); *sampsPerChanWritten = (double)scansWritten ; } }