/*
 * uart16550_drv_mingw.cpp
 *
 */

#ifndef __MINGW32__

void b16550_drv_mingw32_stub()
{
}

#else

#include "xuart_driver.h"

#include <stdint.h>

#include <windows.h>

static void printf(const char*, ...)
{
}

static const int stdout=0;

static void fflush(int)
{
}

//#include "xlru_log.h"

//#include <stdio.h>

#define DEBUG		//use to debug with no serial messages
#define	BOARD		//use to connect to board

// GLOBAL DEFINE

#define DELAY_SEND_CHAR 			10		//mmsec delay between 2 char on com
#define SEND_WITH_DELAY				true	//send single char on com

#ifdef BOARD
#define COM_MASTER 	"\\\\.\\COM8"		//serial port for EIF master, board Nucleo
#define COM_BAUDRATE CBR_9600
#else
#define COM_MASTER 	"\\\\.\\COM3"		//serial port for EIF master, local test with qtterminal
#define COM_BAUDRATE CBR_9600
#endif

#define COM_SLAVE 	"\\\\.\\COM4"		//serial port for LCU slave

// COMMON PARAMETERS

#define COM_BYTESIZE 8;
#define COM_STOPBITS ONESTOPBIT;
#define COM_PARITY NOPARITY;

#ifdef DEBUG
#define SERIAL_TIMEOUT 			2
#define SERIAL_MULTIPLIER  		2
#else
#define SERIAL_TIMEOUT 			50
#define SERIAL_MULTIPLIER  		10
#endif

//#define SERIAL_LOG	//enable log for serial comunication
//#define MESSAGE_LOG		//enable print all char arrived from serial into correct message
#define PRINT_ALL_CHAR	//enable print all char from serial

static HANDLE hSerial;
static DCB dcbSerialParams;
static COMMTIMEOUTS timeouts;
//static DWORD dwBytesRead=0;
//static DWORD dwBytesWrite=0;
static DWORD Status;

static int serial_set_parameter(uint32_t baudrate)
{
	// Set device parameters (9600 baud, 1 start bit, 1 stop bit, no parity)
	dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
	if (GetCommState(hSerial, &dcbSerialParams) == 0)
	{
		CloseHandle(hSerial);
		return 1;
	}

	dcbSerialParams.BaudRate = baudrate; 				//CBR_9600;
	dcbSerialParams.ByteSize = COM_BYTESIZE;			//8;
	dcbSerialParams.StopBits = COM_STOPBITS;			//ONESTOPBIT;
	dcbSerialParams.Parity = EVENPARITY; //baudrate==CBR_9600 ? EVENPARITY : COM_PARITY;				//NOPARITY;
	if(SetCommState(hSerial, &dcbSerialParams) == 0)
	{
		CloseHandle(hSerial);
		return 2;
	}

	return 0;
}

static int serial_set_timeouts(int timeout, int multiplier)
{
	// Set COM port timeout settings
	timeouts.ReadIntervalTimeout = timeout;
	timeouts.ReadTotalTimeoutConstant = timeout;
	timeouts.ReadTotalTimeoutMultiplier = multiplier;
	timeouts.WriteTotalTimeoutConstant = timeout;
	timeouts.WriteTotalTimeoutMultiplier = multiplier;

	timeouts.ReadIntervalTimeout = MAXDWORD;
	timeouts.ReadTotalTimeoutConstant = 0;
	timeouts.ReadTotalTimeoutMultiplier = 0;
	timeouts.WriteTotalTimeoutConstant = 0;
	timeouts.WriteTotalTimeoutMultiplier = 0;

	if(SetCommTimeouts(hSerial, &timeouts) == 0)
	{
		CloseHandle(hSerial);
		return 1;
	}
	return 0;
}

static int serial_open(const char *comNum, uint32_t baudrate)
{
	memset(&dcbSerialParams, 0, sizeof(dcbSerialParams));
	memset(&timeouts, 0, sizeof(timeouts));

	// Open serial port number 1
	//fprintf(stderr, "Opening serial port...");
	hSerial = CreateFile(comNum, GENERIC_READ|GENERIC_WRITE, 0, NULL,
		           	   	     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
	if (hSerial == INVALID_HANDLE_VALUE)
	{
		//fprintf(stderr, "Error\n");
		return 1;	//invalid handler
	}
	else
	{
		//fprintf(stderr, "OK\n");
	}

	int ret = serial_set_parameter(baudrate);

	switch (ret)
	{
		case 0: 	//ok
			break;
		case 1:		//error GetComState
			printf("Error getting device state\n");
#ifdef SERIAL_LOG
			log_error("Error getting device state\n");
#endif
			return 2;
			break;
		case 2:		//error SetComState
			printf("Error setting device parameters\n");
#ifdef SERIAL_LOG
			log_error("Error setting device parameters\n");
#endif
			return 3;
			break;
	}

	if (serial_set_timeouts(SERIAL_TIMEOUT, SERIAL_MULTIPLIER)==1)
	{
		//error SetTimeOuts
		printf("Error setting timeouts\n");
#ifdef SERIAL_LOG
		log_error("Error setting timeouts\n");
#endif
		return 4;
	}

	//EV_TXTEMPTY|EV_RXCHAR
	//Status = SetCommMask(hSerial, EV_RXCHAR);
	Status = SetCommMask(hSerial, EV_TXEMPTY|EV_RXCHAR);

	//serial open ok
	return 0;
}

#if 0
static int serial_close()
{
	// Close serial port
	//printf("Closing serial port...");
#ifdef SERIAL_LOG
	log_info("Closing serial port...");
#endif
	if (CloseHandle(hSerial) == 0)
	{
		printf("Error\n");
		return 1;
	}
	//printf("Serial port closed.\n");
#ifdef SERIAL_LOG
	log_info("Serial port closed.\n");
#endif

	return 0;
}
#endif

static int serial_send(const char * pString)
{
	// Send specified text
	DWORD dwBytesWrite=0;
	printf("Sending bytes...");
#ifdef SERIAL_LOG
	log_info("Sending bytes...");
#endif
	if(!WriteFile(hSerial, pString, strlen(pString), &dwBytesWrite, NULL))
	{
		printf("Error sending bytes.\n");
#ifdef SERIAL_LOG
		log_error("Error sending bytes.\n");
#endif
		CloseHandle(hSerial);
		return 1;
	}
	printf("%d bytes written\n", (int)dwBytesWrite);
#ifdef SERIAL_LOG
	log_info("%d bytes written\n", (int)dwBytesWrite);
#endif
	fflush(stdout);
	return 0;
}

static int serial_send_delay(const char * pString)
{
	// Send specified text
	DWORD dwBytesWrite=0;
	int count_sended = 0;
	printf("Sending bytes...");
#ifdef SERIAL_LOG
	log_info("Sending bytes...");
#endif

	char send_char;
	int len = strlen(pString);
	for (int i = 0; i<len; i++)
	{
		send_char = pString[i];
		if(!WriteFile(hSerial, &send_char, 1, &dwBytesWrite, NULL))
		{
			printf("Error sending bytes.\n");
#ifdef SERIAL_LOG
			log_error("Error sending bytes.\n");
#endif
			CloseHandle(hSerial);
			return 1;
		}
		Sleep(DELAY_SEND_CHAR);
		count_sended = count_sended + dwBytesWrite;
	}
	printf("%d bytes written\n", (int)count_sended);
#ifdef SERIAL_LOG
	log_info("%d bytes written\n", (int)count_sended);
#endif
	fflush(stdout);
	return 0;
}

static int baud_rate;

int xuart_initialize(unsigned int /*ch*/, unsigned int /*speed*/, int /*parity*/)
{
	char* com_port=getenv("EIF_XLRU_PORT");

	if (baud_rate==0)
	{
		baud_rate=COM_BAUDRATE;
		serial_open(com_port ? com_port : COM_MASTER, baud_rate);
	}
	return 0;
}

int xuart_send(unsigned int /*ch*/, const void* data, unsigned int /*len*//*==0 -> "\0" terminated*/)
{
	if (baud_rate==CBR_9600)
		return serial_send(reinterpret_cast<const char*>(data));
	else
	return serial_send_delay(reinterpret_cast<const char*>(data));
}

static unsigned int pendingChar;

int xuart_data_ready(unsigned int /*ch*/)
{
	if (pendingChar!=0xF00000)
		return 1;

	char TempChar=0;
	DWORD dwBytesRead=0;

	BOOL ok=ReadFile( hSerial,           	//Handle of the Serial port
             &TempChar,       		//Temporary character
             sizeof(TempChar),		//Size of TempChar
             &dwBytesRead,    		//Number of bytes read
             NULL);

	if (!ok || (dwBytesRead==0))
		return 0;
	pendingChar=TempChar;
    return 1;
}

int xuart_receive(unsigned int /*ch*/, char* received_char)
{
	char TempChar=0;
	DWORD dwBytesRead=0;

	if (pendingChar!=0xF00000)
	{
		TempChar=pendingChar;
		pendingChar=0xF00000;

	}
	else
	{
		BOOL ok=ReadFile( hSerial,           	//Handle of the Serial port
             &TempChar,       		//Temporary character
             sizeof(TempChar),		//Size of TempChar
             &dwBytesRead,    		//Number of bytes read
             NULL);

		if ((!ok) || (dwBytesRead==0))
				return 0;
	}
	if (received_char)
		*received_char=TempChar;
	return 1;
}



#endif




