//
//
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
//  PURPOSE. IT CAN BE DISTRIBUTED FREE OF CHARGE AS LONG AS THIS HEADER 
//  REMAINS UNCHANGED.
//
//  Email:  yetiicb@hotmail.com
//
//  Copyright (C) 2002-2003 Idael Cardoso. 
//

//#include "Test.h"
#include "SerialPort.h"
#include "stdafx.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSerialPort::CSerialPort() : m_PortHandle(INVALID_HANDLE_VALUE) {

}

CSerialPort::~CSerialPort() {
	Close();
}

bool CSerialPort::Open(LPCTSTR PortName, uint32_t BaudRate, BYTE ByteSize, BYTE Parity, BYTE StopBits, uint32_t DesiredAccess) {
	Close();
	m_PortHandle = CreateFile(PortName, DesiredAccess, 0, NULL, OPEN_EXISTING, 0, 0);
	if (m_PortHandle != INVALID_HANDLE_VALUE) {
		DCB dcb = { 0 };
		CString s;
		dcb.DCBlength = sizeof(dcb);
		GetCommState(m_PortHandle, &dcb);
		//printf("dcb: BaudRate before=%d\n", dcb.BaudRate);
		//printf("dcb: ByteSize before=%d\n", dcb.ByteSize);
		//printf("dcb: StopBits before=%d\n", dcb.StopBits);
		//printf("dcb: Parity before=%d\n", dcb.Parity);
		dcb.BaudRate = BaudRate;
		dcb.ByteSize = ByteSize;
		dcb.StopBits = StopBits;
		dcb.Parity = Parity;
		//printf("dcb: fDsrSensitivity before=%d\n", dcb.fDsrSensitivity);
		//printf("dcb: fOutxCtsFlow before=%d\n", dcb.fOutxCtsFlow);
		//printf("dcb: fOutxDsrFlow before=%d\n", dcb.fOutxDsrFlow);
		//printf("dcb: fInX before=%d\n", dcb.fInX);
		//printf("dcb: fOutX before=%d\n", dcb.fOutX);
		//printf("dcb: fDtrControl before=%d\n", dcb.fDtrControl);
		//printf("dcb: fRtsControl before=%d\n", dcb.fRtsControl);
		dcb.fDsrSensitivity = 0;
		dcb.fOutxCtsFlow = 0;
		dcb.fOutxDsrFlow = 0;
		dcb.fInX = 0;
		dcb.fOutX = 0;
		dcb.fDtrControl = DTR_CONTROL_DISABLE; //DTR and RTS 0
		dcb.fRtsControl = RTS_CONTROL_DISABLE;

		SetCommState(m_PortHandle, &dcb);

		COMMTIMEOUTS touts = { 0 };;
		touts.ReadIntervalTimeout = UINT32_MAX;	// This, plus the zero timeouts causes immediate return
		touts.ReadTotalTimeoutMultiplier = 0;
		touts.ReadTotalTimeoutConstant = 0;
		touts.WriteTotalTimeoutConstant = 1;
		touts.WriteTotalTimeoutMultiplier = 0;
		SetCommTimeouts(m_PortHandle, &touts);

		//SetCommMask (m_PortHandle, EV_CTS | EV_DSR | EV_RING | EV_RLSD);
		PurgeComm(m_PortHandle, PURGE_TXCLEAR | PURGE_RXCLEAR);
		return true;
	} else {
		return false; // Use GetLastError() to know the reason
	}
}

void CSerialPort::Close() {
	if (m_PortHandle != INVALID_HANDLE_VALUE) {
		CloseHandle(m_PortHandle);
		m_PortHandle = INVALID_HANDLE_VALUE;
	}
}

bool CSerialPort::IsOpen() {
	return (m_PortHandle != INVALID_HANDLE_VALUE);
}

uint32_t CSerialPort::Read(LPVOID Buffer, uint32_t BufferSize) {
	DWORD Res(0);
	if (m_PortHandle != INVALID_HANDLE_VALUE) {
		ReadFile(m_PortHandle, Buffer, BufferSize, &Res, NULL);
	}
	return Res;
}

uint32_t CSerialPort::Write(const LPVOID Buffer, uint32_t BufferSize) {
	DWORD Res(0);
	if (m_PortHandle != INVALID_HANDLE_VALUE) {
		(void)WriteFile(m_PortHandle, Buffer, BufferSize, &Res, NULL);
	}
	return Res;
}

bool CSerialPort::Get_CD_State() {
	if (m_PortHandle != INVALID_HANDLE_VALUE) {
		DWORD ModemStat;
		if (GetCommModemStatus(m_PortHandle, &ModemStat)) {
			return (ModemStat & MS_RLSD_ON) > 0; //Not sure
		}
	}
	return false;
}

bool CSerialPort::Get_CTS_State() {
	if (m_PortHandle != INVALID_HANDLE_VALUE) {
		DWORD ModemStat;
		if (GetCommModemStatus(m_PortHandle, &ModemStat)) {
			return (ModemStat & MS_CTS_ON) > 0;
		}
	}
	return false;
}

bool CSerialPort::Get_DSR_State() {
	if (m_PortHandle != INVALID_HANDLE_VALUE) {
		DWORD ModemStat;
		if (GetCommModemStatus(m_PortHandle, &ModemStat)) {
			return (ModemStat & MS_DSR_ON) > 0;
		}
	}
	return false;
}

bool CSerialPort::Get_RI_State() {
	if (m_PortHandle != INVALID_HANDLE_VALUE) {
		DWORD ModemStat;
		if (GetCommModemStatus(m_PortHandle, &ModemStat)) {
			return (ModemStat & MS_RING_ON) > 0;
		}
	}
	return false;
}

bool CSerialPort::Set_DTR_State(bool state) {
	if (m_PortHandle != INVALID_HANDLE_VALUE) {
		if (0 == EscapeCommFunction(m_PortHandle, (state ? SETDTR : CLRDTR))) {
			return false;
		}
	}
	return true;
}

bool CSerialPort::Get_DTR_State() {
	if (m_PortHandle != INVALID_HANDLE_VALUE) {
		DWORD ModemStat;
		if (GetCommModemStatus(m_PortHandle, &ModemStat)) {
			return (ModemStat & MS_DSR_ON) > 0; //Not sure
		}
	}
	return false;
}

bool CSerialPort::Set_RTS_State(bool state) {
	if (m_PortHandle != INVALID_HANDLE_VALUE) {
		if (0 == EscapeCommFunction(m_PortHandle, (state ? SETRTS : CLRRTS))) {
			return false;
		}
	}
	return true;
}

bool CSerialPort::Get_RTS_State() {
	if (m_PortHandle != INVALID_HANDLE_VALUE) {
		DWORD ModemStat;
		if (GetCommModemStatus(m_PortHandle, &ModemStat)) {
			return (ModemStat & MS_CTS_ON) > 0; //Not sure
		}
	}
	return false;
}
