//Gateway routine void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { TaskHandle task; int32 numSampsPerChan; float64 timeout; uInt32 numChannels; int32 totalNumSamples; uInt32 arraySizeInSamples; uInt32 arraySizeInBytes; int32 sampsRead; int32 numBytesPerSamp; int16 *dataBuffer; int32 status; int32 errorStringSize; char *errorString; double *sampsReadOutput; //Parse input arguments task = (TaskHandle)mxGetScalar(prhs[0]); numSampsPerChan = (int32)mxGetScalar(prhs[1]); timeout = (float64)mxGetScalar(prhs[2]); arraySizeInSamples = (uInt32)mxGetScalar(prhs[3]); //Determine # of channels and amt. of memory to allocate DAQmxGetTaskNumChans(task, &numChannels); totalNumSamples = arraySizeInSamples * numChannels; arraySizeInBytes = totalNumSamples * sizeof(int16); //Create memory for output arguments plhs[0] = mxCreateNumericMatrix(totalNumSamples, 1, mxINT16_CLASS, mxREAL); plhs[1] = mxCreateDoubleScalar(0); dataBuffer = (int16*)mxGetPr(plhs[0]); sampsReadOutput = mxGetPr(plhs[1]); //Call DAQmx function status = (int32) DAQmxReadRaw(task, numSampsPerChan, timeout, dataBuffer, arraySizeInBytes, &sampsRead, &numBytesPerSamp, NULL); //Return output buffer if (!status) { mexPrintf("Successfully read %d samples of data\n", sampsRead); *sampsReadOutput = (double)sampsRead; } else { //Display error string errorStringSize = DAQmxGetErrorString(status,NULL,0); //Gets size of buffer errorString = (char *)mxCalloc(errorStringSize,sizeof(char)); DAQmxGetErrorString(status,errorString,errorStringSize); mexPrintf("ERROR in %s: %s\n", mexFunctionName(), errorString); mxFree(errorString); //Return an empty array insead mxDestroyArray(plhs[0]); //I think this is kosher plhs[0] = mxCreateNumericMatrix(0, 0, mxINT16_CLASS, mxREAL); } }
int NationalInstrumentsDAQ::writeAO(float64 *data) { int32 written, N = _config->ao_samples_per_waveform(); #if 0 { uInt32 nchan; char buf[1024], name[1024]; memset(buf ,0,sizeof(buf )); memset(name,0,sizeof(name)); DAQWRN( DAQmxGetTaskName(_ao.daqtask,name,sizeof(name)) ); DAQWRN( DAQmxGetTaskNumChans(_ao.daqtask,&nchan) ); DAQWRN( DAQmxGetTaskChannels(_ao.daqtask,buf,sizeof(buf)) ); HERE; debug("NI-DAQmx Task (%s) has %d channels"ENDL"\t%s"ENDL, name, nchan, buf); while(nchan--) { DAQWRN( DAQmxGetNthTaskChannel(_ao.daqtask, 1+nchan, buf, sizeof(buf)) ); DAQWRN( DAQmxGetPhysicalChanName(_ao.daqtask, buf, buf, sizeof(buf)) ); debug("\t%d:\t%s"ENDL,nchan,buf); } } { FILE *fp = fopen("NationalInstrumentsDAQ_writeAO.f64","wb"); fwrite(data,sizeof(f64),3*N,fp); fclose(fp); } #endif DAQJMP( DAQmxWriteAnalogF64(_ao.daqtask, N, 0, // autostart? 1.0, // timeout (s) - to write - 0 causes write to fail if blocked at all DAQmx_Val_GroupByChannel, data, &written, NULL)); Guarded_Assert( written == N ); return 0; // success Error: return 1; // fail }
//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 ; } }