Ejemplo n.º 1
0
//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());

}
Ejemplo n.º 2
0
// [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());
	}

}