/****************************************************
*
* GetSerialData.cpp
*
* --Educational Use Only
* 
* For use with MATLAB and the ECE320/ECE420
* DSP serial interface.
*
* This is a MEX-FILE for matlab. 
* To compile type: "mex GetSerialData.cpp" into prompt.
*
* After compiling, type: 
*			GetSerialData('Help'); 
* for usage instructions.
*
* Credits:
*   -Modified for use with MATLAB by Jason Laska, April 2004
*   http://www.uiuc.edu/~laska
*   -Original code for SerialTerm (serial terminal program
*   from which this was taken)
*   by Albrecht Schmidt, Lancaster University - Oct 2001
*   http://www.comp.lancs.ac.uk/~albrecht 
*   Albrecht@comp.lancs.ac.uk
*   -SerialTerm was based on an example from Robert Mashlan
*   see http://r2m.com/~rmashlan/
*
*****************************************************/

#include "stdafx.h"
#define STRICT
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mex.h"


//Global Declarations
double *SerialData;
int NumPoints;
int Sign;


void help() 
{
	printf("Format:  \n");
	printf("		y = GetSerialData('port', baud, size, sign);\n");
	printf("Ports:\n");
	printf("		'com1', 'com2' \n");
	printf("Bauds:  \n");
	printf("		300, 4800, 9600, 19200, 38400, 57600, 115200, 230400\n");
	printf("Size:\n");
	printf("		A Row Vector Size of your choice! \n\n");
	printf("Sign(Optional): \n");
	printf("		Unsigned(Default) = 0			Signed = 1 \n\n");
	printf("**Note: 'port' must be entered in quotes. \n");
	printf("**Note: Other serial interfacing preferences can be  \n");
	printf("		modified in the source. \n");
	printf("-----------------------------------------------------------\n");
}




void PrintError(LPCSTR str)
{
   LPVOID lpMessageBuffer;
   int error = GetLastError();
   FormatMessage(
      FORMAT_MESSAGE_ALLOCATE_BUFFER |
      FORMAT_MESSAGE_FROM_SYSTEM,
      NULL,
      error,
      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //The user default language
      (LPTSTR) &lpMessageBuffer,
      0,
      NULL
   );
   printf("%s: (%d) %s\n\n",str,error,lpMessageBuffer);
   help();
   LocalFree( lpMessageBuffer );
}




void Receive(HANDLE h)
{
    HANDLE hconn = GetStdHandle(STD_OUTPUT_HANDLE);
    DWORD mask;
    DWORD id, i;
    OVERLAPPED ov;
    int go;
	int StopStream=0;
	char uns;


	//Initialization and Set-Up
   ZeroMemory(&ov,sizeof(ov));

   // create event for overlapped I/O
   ov.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
   if(ov.hEvent == INVALID_HANDLE_VALUE)
      PrintError("E006_CreateEvent failed");

   // wait for received characters
   if(!SetCommMask(h,EV_RXCHAR))
      PrintError("E007_SetCommMask failed");


   //Get the Data 
   while(1)
   {
      // get the event mask
      if( !WaitCommEvent(h,&mask,&ov) ) 
      {
         DWORD e = GetLastError();
         if( e == ERROR_IO_PENDING ) 
         {
            DWORD r;
            if( !GetOverlappedResult(h,&ov,&r,TRUE) ) 
            {
               PrintError("E008_GetOverlappedResult failed");
               break;
            }
         } 
         else 
         {
            PrintError("E009_WaitCommEvent failed");
            break;
         }
      }

      //There was an error getting the mask.
      if(mask == 0) 
	  {
         break;
      }

      if( mask & EV_RXCHAR) 
      {
         char buf[10];
         DWORD read;
         do 
         {
            read = 0;
            if( !ReadFile(h,buf,sizeof(buf),&read,&ov) ) 
            {
               if( GetLastError() == ERROR_IO_PENDING ) 
               {
                  if( !GetOverlappedResult(h,&ov,&read,TRUE) ) 
                  {
                     PrintError("E010_GetOverlappedResult failed");
                     break;
                  }
               } 
               else 
               {
                  PrintError("E011_ReadFile failed");
                  break;
               }
            }
            
            //Read Data 
            for (i=0; i<read; i++) 
            {
                //Write to matlab vector
                if(StopStream < NumPoints)
                {
                    SerialData[StopStream] = buf[i];
					if(Sign == 0)
						SerialData[StopStream] = (unsigned char)SerialData[StopStream];
					StopStream++;
                }
                else
				{
					return;
				}
            }
        } while(read);
      }
      //Clear Mask
      mask = 0;
   }
   //Close the Event
   CloseHandle(ov.hEvent);
 }
  
  



void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
	//Declarations
	char *In0;
    int Length0;
	mxArray *OutArray;
	int Baud;


	//Convert the Inputs
	if((nrhs >= 3)&&(nlhs ==1))
	{
		//Get Port
		if (mxIsChar(prhs[0]) != 1)
		{
			mexErrMsgTxt("Input 1 must be a string 'com1' or 'com2' ");
		}
		else
		{
			Length0 = mxGetN(prhs[0])+1;
			In0 = mxCalloc(Length0, sizeof(char));
			mxGetString(prhs[0],In0,Length0);
		}
		//Get Baud
		Baud = (int)mxGetScalar(prhs[1]);
		//Get Size
		NumPoints = (int)mxGetScalar(prhs[2]);

		//Get Sign
		Sign = 0;
		if(nrhs == 4)
		{
			Sign = (int)mxGetScalar(prhs[3]);
		}

		//Set up Output array
		plhs[0] = mxCreateDoubleMatrix(1,NumPoints,mxREAL);
		SerialData = mxGetPr(plhs[0]);
	}

	
   //I Dont know why, but the compiler needs this conditional here also.
   //Set up Port and get Data
   if((nrhs >= 3)&&(nlhs ==1)) 
   {
      // open port for overlapped I/O
      HANDLE h = CreateFile(In0, GENERIC_READ|GENERIC_WRITE, 0,NULL, OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);

      if(h == INVALID_HANDLE_VALUE) 
      {
         PrintError("E012_Failed to open port");
      } 
      else 
      {
         // set timeouts
         COMMTIMEOUTS cto = { 2, 1, 1, 0, 0 };
         DCB dcb;
         if(!SetCommTimeouts(h,&cto))
            PrintError("E013_SetCommTimeouts failed");

         //Set up Serial Port Attributes
         memset(&dcb,0,sizeof(dcb));
         dcb.DCBlength = sizeof(dcb);
         //dcb.BaudRate = 19200;
         dcb.BaudRate = Baud;
         dcb.fBinary = 1;
		 dcb.fDtrControl = DTR_CONTROL_ENABLE;
		 dcb.fRtsControl = RTS_CONTROL_ENABLE;
		 // dcb.fOutxCtsFlow = 1;
  		 // dcb.fRtsControl = DTR_CONTROL_HANDSHAKE;
         dcb.Parity = NOPARITY;
         dcb.StopBits = ONESTOPBIT;
         dcb.ByteSize = 8;

         if(!SetCommState(h,&dcb))
            PrintError("E014_SetCommState failed");

		
        //Get Data
        Receive(h);
        CloseHandle(h);
      }
   } 
   else 
   {
	    if(nlhs == 1)
			plhs[0] = mxCreateDoubleMatrix(1,1,mxREAL);
	    printf("														\n");
        printf("--------------        GetSerialData       -----------------\n");
        printf("  University of Illinois Urbana-Champaign ECE320/420 2004  \n");
		printf("														\n");
        help();
   }
   return;
}


