// Zmodlib.cpp


#include "zmcore.h"
#include "Zmodlib.h"
#include "error.h"
#include "unused.h"

HANDLE hSerCom;
#define READ_TIMEOUT      500      // milliseconds
#define INQUESIZE		5000
#define	OUTQUESIZE		5000

/*****************************************************************/

int InitCom(void)
{
	DCB dcb;
	BOOL fSuccess;
	char *pcCommPort = "COM2";

	COMMTIMEOUTS timeouts;
	timeouts.ReadIntervalTimeout = 0; 
	timeouts.ReadTotalTimeoutMultiplier = 0;
	timeouts.ReadTotalTimeoutConstant = 10;
	timeouts.WriteTotalTimeoutMultiplier = 0;
	timeouts.WriteTotalTimeoutConstant = 0;


	hSerCom = CreateFile( pcCommPort,
					GENERIC_READ | GENERIC_WRITE,
					0,    // must be opened with exclusive-access
					NULL, // no security attributes
					OPEN_EXISTING, // must use OPEN_EXISTING
					FILE_FLAG_OVERLAPPED,    // overlapped I/O
					NULL  // hTemplate must be NULL for comm devices
					);

	if (hSerCom == INVALID_HANDLE_VALUE) 
	{
		// Handle the error.
		printf ("CreateFile failed with error %d.\n", GetLastError());
		return (1);
	}

	// Set Rx and Tx buffer sizes large enough for ZMODEM packets
	SetupComm (hSerCom, INQUESIZE, OUTQUESIZE);


	// Build on the current configuration, and skip setting the size
	// of the input and output buffers with SetupComm.

	fSuccess = GetCommState(hSerCom, &dcb);

	if (!fSuccess) 
	{
		// Handle the error.
		printf ("GetCommState failed with error %d.\n", GetLastError());
		return (2);
	}

	// Fill in DCB: 115,200 bps, 8 data bits, no parity, and 1 stop bit.

	dcb.ByteSize = 8;             // data size, xmit, and rcv
	dcb.StopBits = ONESTOPBIT;    // one stop bit
	dcb.DCBlength = sizeof(dcb);      /* sizeof(DCB) */
	dcb.BaudRate = CBR_19200;     // set the baud rate
	dcb.Parity = NOPARITY;        // no parity bit
    dcb.fOutxCtsFlow = FALSE;		/* CTS handshaking on output */
    dcb.fOutxDsrFlow = FALSE;		/* DSR handshaking on output */
    dcb.fDtrControl = DTR_CONTROL_DISABLE;  /* DTR Flow control  */
    dcb.fDsrSensitivity = FALSE;	/* DSR Sensitivity */
    dcb.fTXContinueOnXoff = TRUE; /* Continue TX when Xoff sent */
    dcb.fOutX = FALSE;       /* Enable output X-ON/X-OFF */
    dcb.fInX = FALSE;        /* Enable input X-ON/X-OFF */
    dcb.fNull = FALSE;       /* Enable Null stripping */
    dcb.fRtsControl = RTS_CONTROL_DISABLE;  /* Rts Flow control */
    dcb.fAbortOnError = FALSE;	/* Abort all reads and writes on Error */
  
	fSuccess = SetCommState(hSerCom, &dcb);
	if (!fSuccess) 
	{
		// Handle the error.
		printf ("SetCommState failed with error %d.\n", GetLastError());
		return (3);
	}

	if (!SetCommTimeouts(hSerCom, &timeouts))
	// Error setting time-outs.


	printf ("Serial port %s successfully reconfigured.\n", pcCommPort);
	return 0;
}

/*********************************************************************************/

void CloseCom(void)
{
	CloseHandle(hSerCom);
}

/*********************************************************************************/
BOOL WriteSerPort(char *lpBuf, DWORD dwToWrite)
{
   OVERLAPPED osWrite = {0};
   DWORD dwWritten;
   BOOL fRes;

   // Create this writes OVERLAPPED structure hEvent.
   osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
   if (osWrite.hEvent == NULL)
      // Error creating overlapped event handle.
      return FALSE;

   // Issue write.
   if (!WriteFile(hSerCom, lpBuf, dwToWrite, &dwWritten, &osWrite)) {
      if (GetLastError() != ERROR_IO_PENDING) { 
         // WriteFile failed, but it isn't delayed. Report error and abort.
         fRes = FALSE;
      }
      else {
         // Write is pending.
         if (!GetOverlappedResult(hSerCom, &osWrite, &dwWritten, TRUE))
            fRes = FALSE;
         else
            // Write operation completed successfully.
            fRes = TRUE;
      }
   }
   else
      // WriteFile completed immediately.
      fRes = TRUE;

   CloseHandle(osWrite.hEvent);
   return fRes;
}

/**********************************************************************************/

BOOL ReadSerPort(char* lpBuf, DWORD dwToRead, DWORD *dwRead)
{
	DWORD dwRes;
	BOOL fWaitingOnRead = FALSE;
	OVERLAPPED osReader = {0};


	// Create the overlapped event. Must be closed before exiting
	// to avoid a handle leak.
	osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

	if (osReader.hEvent == NULL)
	{
		// Error creating overlapped event; abort.
		printf("\nError Create Reader Event");
		return 1;
	}

	while(1)
	{
		if (!fWaitingOnRead)
		{
			// Issue read operation.
			if (!ReadFile(hSerCom, lpBuf, dwToRead, dwRead, &osReader))
			{
				if (GetLastError() != ERROR_IO_PENDING)     // read not delayed?
					printf("\nError in GetLastError.");
				else
					fWaitingOnRead = TRUE;
			}
			else
			{    
				// read completed immediately
				CloseHandle(osReader.hEvent);
				return 0;
			}
		}


		if (fWaitingOnRead)
		{
			dwRes = WaitForSingleObject(osReader.hEvent, READ_TIMEOUT);
			switch(dwRes)
			{
				// Read completed.
				case WAIT_OBJECT_0:
					if (!GetOverlappedResult(hSerCom, &osReader, dwRead, FALSE))
					{
						printf("\nError in GetOverlappedResult");
						return 1;
					}
					else
					{
						// Read completed successfully.
						CloseHandle(osReader.hEvent);
						return 0;
						break;
					}

				case WAIT_TIMEOUT:
					// Operation isn't complete yet, so loop back around.
					break;                       

				default:
					// Error in the WaitForSingleObject; abort.
					printf("\nError in WaitForSingleObject.");
					CloseHandle(osReader.hEvent);
					return 1;
					break;
			}
		}
	}

}
/********************************************************/
