
//#include <windows.h>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <WinSock2.h>
#include "SerialPort.h"
#include <fileapi.h>
#include <winnt.h>


//获取继电器板子对应的串口名称
bool xGet_relay_com(char* com_name)
{
	return true;
}

SerialPort::SerialPort()
{

}

SerialPort::~SerialPort()
{

}

bool SerialPort::open(const char* portname, int baudrate, char parity, char databit, char stopbit, FlowControl fc, char synchronizeflag)
{
	this->synchronizeflag = synchronizeflag;
	HANDLE hCom = NULL;
	
	if (this->synchronizeflag)
	{
		std::cout << "uart W/R type: synchronizeflag\n" << synchronizeflag << std::endl;
		//同步方式
		hCom = CreateFile(portname,
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_EXISTING,
			0,
			NULL);
	}
	else
	{
		std::cout << "uart W/R type: asynchronousflag\n" << synchronizeflag << std::endl;
		//异步方式
		hCom = CreateFile(portname,
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_EXISTING,
			FILE_FLAG_OVERLAPPED,
			NULL);
	}
	if (hCom == (HANDLE)-1)
	{
		cout << "open uart file fail" << endl;
		return false;
	}

	if (!SetupComm(hCom, 1024, 1024))
	{
		return false;
	}

	DCB dcb;

	if (!GetCommState(hCom, &dcb))
	{
		return false;
	}

	memset(&dcb, 0, sizeof(dcb));
	dcb.DCBlength = sizeof(dcb);
	dcb.BaudRate = baudrate;
	dcb.ByteSize = databit;

	switch (parity)
	{
	case 0:
		dcb.Parity = NOPARITY;
		break;
	case 1:
		dcb.Parity = ODDPARITY;
		break;
	case 2:
		dcb.Parity = EVENPARITY;
		break;
	case 3:
		dcb.Parity = MARKPARITY;
		break;
	}

	switch (stopbit)
	{
	case 1:
		dcb.StopBits = ONESTOPBIT;
		break;
	case 2:
		dcb.StopBits = TWOSTOPBITS;
		break;
	case 3:
		dcb.StopBits = ONE5STOPBITS;
		break;
	}

	dcb.fDsrSensitivity = FALSE;
	dcb.fTXContinueOnXoff = FALSE;
	dcb.fRtsControl = RTS_CONTROL_DISABLE;
	dcb.fDtrControl = DTR_CONTROL_ENABLE;

	switch (fc)
	{
		case NoFlowControl:
		{
			dcb.fOutxCtsFlow = FALSE;
			dcb.fOutxDsrFlow = FALSE;
			dcb.fOutX = FALSE;
			dcb.fInX = FALSE;
			break;
		}
		case CtsRtsFlowControl:
		{
			dcb.fOutxCtsFlow = TRUE;
			dcb.fOutxDsrFlow = FALSE;
			dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
			dcb.fOutX = FALSE;
			dcb.fInX = FALSE;
			break;
		}
		case CtsDtrFlowControl:
		{
			dcb.fOutxCtsFlow = TRUE;
			dcb.fOutxDsrFlow = FALSE;
			dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
			dcb.fOutX = FALSE;
			dcb.fInX = FALSE;
			break;
		}
		case DsrRtsFlowControl:
		{
			dcb.fOutxCtsFlow = FALSE;
			dcb.fOutxDsrFlow = TRUE;
			dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
			dcb.fOutX = FALSE;
			dcb.fInX = FALSE;
			break;
		}
		case DsrDtrFlowControl:
		{
			dcb.fOutxCtsFlow = FALSE;
			dcb.fOutxDsrFlow = TRUE;
			dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
			dcb.fOutX = FALSE;
			dcb.fInX = FALSE;
			break;
		}
		case XonXoffFlowControl:
		{
			dcb.fOutxCtsFlow = FALSE;
			dcb.fOutxDsrFlow = FALSE;
			dcb.fOutX = TRUE;
			dcb.fInX = TRUE;
			dcb.XonChar = 0x11;
			dcb.XoffChar = 0x13;
			dcb.XoffLim = 100;
			dcb.XonLim = 100;
			break;
		}

	}//end switch

	if (!SetCommState(hCom, &dcb))
	{
		return false;
	}

	COMMTIMEOUTS TimeOuts;
#if 1
	TimeOuts.ReadIntervalTimeout = 1000;
	TimeOuts.ReadTotalTimeoutMultiplier = 500;
	TimeOuts.ReadTotalTimeoutConstant = 500;
	TimeOuts.WriteTotalTimeoutMultiplier = 500;
	TimeOuts.WriteTotalTimeoutConstant = 2000;
#else
	TimeOuts.ReadIntervalTimeout = 0;
	TimeOuts.ReadTotalTimeoutMultiplier = 0;
	TimeOuts.ReadTotalTimeoutConstant = 5000;
	TimeOuts.WriteTotalTimeoutMultiplier = 0;
	TimeOuts.WriteTotalTimeoutConstant = 0;
#endif
	SetCommTimeouts(hCom, &TimeOuts);//超时时间设置

	PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR);

	memcpy(pHandle, &hCom, sizeof(hCom));

	return true;

}
void SerialPort::close()
{
	HANDLE hCom = *(HANDLE*)pHandle;
	CloseHandle(hCom);
}

int SerialPort::send(const void *buf,int len)
{
	HANDLE hCom = *(HANDLE*)pHandle;

	if (this->synchronizeflag)
	{
		// 同步方式
		DWORD dwBytesWrite = len;
		BOOL bWriteStat = WriteFile(hCom,
			buf,
			dwBytesWrite,
			&dwBytesWrite,
			NULL);

		if (!bWriteStat)
		{
			return 0;
		}
		return dwBytesWrite;
	}
	else
	{
		DWORD dwBytesWrite = len;
		DWORD dwErrorFlags;
		COMSTAT comStat;
		OVERLAPPED m_osWrite;

		//创建一个用于OVERLAPPED的事件处理，不会真正用到，但系统要求这么做
		memset(&m_osWrite, 0, sizeof(m_osWrite));
		m_osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, "WriteEvent");

		ClearCommError(hCom, &dwErrorFlags, &comStat);
		BOOL bWriteStat = WriteFile(hCom,
			buf,
			dwBytesWrite,
			&dwBytesWrite,
			&m_osWrite);
		if (!bWriteStat)
		{
			if (GetLastError() == ERROR_IO_PENDING)
			{
				WaitForSingleObject(m_osWrite.hEvent, 1000);
			}
			else
			{
				ClearCommError(hCom, &dwErrorFlags, &comStat);
				CloseHandle(m_osWrite.hEvent);
				return 0;
			}
		}
		return dwBytesWrite;
	}
}

int SerialPort::receive(void *buf,int maxlen)
{
	HANDLE hCom = *(HANDLE*)pHandle;

	if (this->synchronizeflag)
	{
		//同步方式
		DWORD wCount = maxlen;
		BOOL bReadStat = ReadFile(hCom,
			buf,
			wCount,
			&wCount,
			NULL);
		if (!bReadStat)
		{
			return 0;
		}
		return wCount;
	}
	else
	{
		DWORD wCount = maxlen;
		DWORD dwErrorFlags;
		COMSTAT comStat;
		OVERLAPPED m_osRead;

		memset(&m_osRead, 0, sizeof(m_osRead));
		m_osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, "ReadEvent");

		ClearCommError(hCom, &dwErrorFlags, &comStat);
		if (!comStat.cbInQue)return 0;

		BOOL bReadStat = ReadFile(hCom,
			buf,
			wCount,
			&wCount,
			&m_osRead);
		if (!bReadStat)
		{
			if (GetLastError() == ERROR_IO_PENDING)
			{
				GetOverlappedResult(hCom, &m_osRead, &wCount, TRUE);
			}
			else
			{
				ClearCommError(hCom, &dwErrorFlags, &comStat);
				CloseHandle(m_osRead.hEvent);
				return 0;
			}
		}
		return wCount;
	}
	
}

