#include "uartcom.h"
#include <string.h>
//#include <wx/msgdlg.h>
#include <windows.h>


UartCom::UartCom(void) : wxThread()
{
//    wxMessageBox(_T("Uartcom ctor"));
    hComm = INVALID_HANDLE_VALUE;
    OutLen = 0;
    InLen = 0;
    RecvLen = 0;
    Create();
    Resume();
}

UartCom::~UartCom()
{
    ClosePort();
}

unsigned char * UartCom::Read(int *cb)
{
    wxCriticalSectionLocker Locker(TheLock);

    if (OutLen) {
        RecvLen = OutLen;
        *cb = RecvLen;
        return OutBuf;
    }
    else {
        *cb = 0;
        return NULL;
    }
}

void UartCom::ClearPacket(void)
{
    memmove(OutBuf, OutBuf+RecvLen, OutLen - RecvLen);
    OutLen -= RecvLen;
    RecvLen = 0;
}

void UartCom::Write(void *buf, int len)
{
    DWORD cb;

    WriteFile(hComm, buf, len, &cb, NULL);
}

void UartCom::MoveBuf(void)
{
    wxCriticalSectionLocker Locker(TheLock);
    int mlen;

    mlen = InLen;

    if (OutLen+mlen > UARTCOM_BUFSIZE) mlen = UARTCOM_BUFSIZE - OutLen;

    memcpy(OutBuf+OutLen, InBuf, mlen);
    OutLen += mlen;
    memmove(InBuf, InBuf+mlen, mlen);
    InLen -= mlen;
}

void UartCom::OpenPort(const char *portname, int baud)
{
	HANDLE h;
	COMMTIMEOUTS tw;
	DCB dcb;

	h=CreateFileA(portname,
		GENERIC_READ | GENERIC_WRITE,
		0,    // comm devices must be opened w/exclusive-access
		NULL, // no security attrs
		OPEN_EXISTING, // comm devices must use OPEN_EXISTING
		0,    // overlapped I/O
		NULL);  // hTemplate must be NULL for comm devices

	if (h==INVALID_HANDLE_VALUE) return;

	tw.ReadIntervalTimeout=10;	//Modbus RTU mode max. timeout (ms)
	tw.ReadTotalTimeoutMultiplier=0;
	tw.ReadTotalTimeoutConstant=10;
	tw.WriteTotalTimeoutMultiplier=0;
	tw.WriteTotalTimeoutConstant=0;

	if (!SetCommTimeouts(h,&tw)) {
	  CloseHandle(h);
	  return;
	}

	if (!GetCommState(h,&dcb)) {
	  CloseHandle(h);
	  return;
	}
	dcb.ByteSize=8;
	dcb.Parity=0;
	dcb.StopBits=0;
	dcb.BaudRate=baud;
	dcb.fRtsControl = 1;
	dcb.fDtrControl = 0;
	if (!SetCommState(h,&dcb)) {
	  CloseHandle(h);
	  return;
	}

	hComm=h;
}

void UartCom::ClosePort(void)
{
    CloseHandle(hComm);
    hComm = INVALID_HANDLE_VALUE;
}

bool UartCom::IsConnected(void)
{
    return hComm != INVALID_HANDLE_VALUE;
}

void* UartCom::Entry(void)
{
    DWORD cb;

    while (!TestDestroy()) {
        if (hComm != INVALID_HANDLE_VALUE) {
            ReadFile(hComm, InBuf+InLen, UARTCOM_BUFSIZE-InLen, &cb, NULL);
            if (cb>0) {
                InLen += cb;
                MoveBuf();
            }
            else Sleep(0);
        }
        else Sleep(0);
    }
    return NULL;
}
