//---------------------------------------------------------------------------
#pragma hdrstop
#include "stdafx.h"
//---------------------------------------------------------------------------
#include "ComPort.h"
#include "Windows.h"

#include <stdTools.h>

//#include <vcl.h>
#include <sstream>
//---------------------------------------------------------------------------
#if defined( _BORLAND )
	#pragma package(smart_init)
#endif
//---------------------------------------------------------------------------
/*template <typename T>
std::string toString2(T val)
{
	std::ostringstream oss;
	oss << val;
	return oss.str();

}*/
//---------------------------------------------------------------------------
/*std::string getComName(int num)
{
//	if(num<10) return "COM"+IntToStr(num);
//	else
		return "\\\\.\\COM"+toString2(num);
}*/
//------------------------------------------------------------------------------
ComPort::ComPort()
{
	m_time=500; //Время по умолчанию
	hCom=0;
	ComNumber=1;
	BaudRate=115200;
	bOpen=false;
}
//------------------------------------------------------------------------------
ComPort::~ComPort()
{
}
//------------------------------------------------------------------------------
void ComPort::CheckBaudRate()
{
	if(BaudRate==0) BaudRate=1200;
	if(BaudRate==1) BaudRate=2400;
	if(BaudRate==2) BaudRate=4800;
	if(BaudRate==3) BaudRate=9600;
	if(BaudRate==4) BaudRate=19200;
	if(BaudRate==5) BaudRate=38400;
	if(BaudRate==6) BaudRate=57600;
	if(BaudRate==7) BaudRate=115200;
}
//------------------------------------------------------------------------------
bool ComPort::Open(int ComNumber)
{
	if(hCom!=0) Close(); //Если открыт ком порт закроем
	this->ComNumber=ComNumber;
	std::string port="\\\\.\\COM";
	port+=IntToStdStr(ComNumber);

	hCom = CreateFileA(port.c_str(), GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	if(hCom == INVALID_HANDLE_VALUE) bOpen=false; else bOpen=true;
	return bOpen;
}
//------------------------------------------------------------------------------
bool ComPort::Close()
{
	CloseHandle(hCom);
	if(hCom == INVALID_HANDLE_VALUE){ hCom=0; return false; } else { hCom=0; bOpen=false; return true; }
}
//------------------------------------------------------------------------------
//num - номер настроек под разное оборудование (num=1 то атоловские настройки для ком порта)
bool ComPort::Setup(int num)
{
	CheckBaudRate(); //из 1,2,3... в 1200,2400,4800...

	int RxBufferSize = 2048; 
	int TxBufferSize = 2048;
	if(!SetupComm(hCom, RxBufferSize, TxBufferSize)) return false;

	DCB dcb;
	if(num==0) //Настройки для ПОРТ 300 100
	{
      		//if(!GetCommState(hCom, &dcb)) return false;
		memset(&dcb,0,sizeof(dcb));
		dcb.DCBlength = sizeof (DCB);
		dcb.BaudRate=BaudRate;
		dcb.fBinary=1;
                //dcb.fDtrControl=DTR_CONTROL_ENABLE; //Без этого 0x03 не принималось с принтера а потом начала принимать и без...
		dcb.fRtsControl=RTS_CONTROL_ENABLE;
		dcb.XonLim=2048;
		dcb.XoffLim=512;
		dcb.ByteSize=8;
		dcb.XonChar=17;
		dcb.XoffChar=19;
	}else
	if(num==1) //Настройки для Аура-01ФР-KZ
	{
		memset(&dcb,0,sizeof(dcb));
		dcb.DCBlength = sizeof (DCB);
		dcb.BaudRate=BaudRate;
		dcb.fBinary=1;
		dcb.XonLim=2048;
		dcb.XoffLim=512;
		dcb.ByteSize=8;
		dcb.XonChar=17;
		dcb.XoffChar=19;
        }else
	if(num==2) //Настройки для CashCode
	{
		if(!GetCommState(hCom, &dcb)) return false;
		dcb.BaudRate=BaudRate;
		dcb.ByteSize=8;
		dcb.Parity=NOPARITY;
		dcb.StopBits=ONESTOPBIT;
		dcb.fDtrControl=DTR_CONTROL_ENABLE;
	}else //Свои настройки
	{
		memset(&dcb,0,sizeof(dcb));
		if(!GetCommState(hCom, &dcb)) return false; //Берём текущие настройки

		dcb.BaudRate = BaudRate;		// Current baud rate (115200)
		dcb.fBinary = TRUE;				// В винде только двоичный режим всегда 1
		dcb.fParity = TRUE;				// Если этот член структуры - ИСТИНА (TRUE), выполняется проверка четности и сообщается об ошибках...
		dcb.ByteSize = 8;				// Number of bits/byte, 4-8

		dcb.Parity = NOPARITY;			// Используемая схема четности. (EVENPARITY Проверка по четности MARKPARITY Проверка четности по метке NOPARITY Без проверки четности ODDPARITY Проверка по нечетности SPACEPARITY Проверка четности по паузе)
		dcb.fTXContinueOnXoff = FALSE;	// Если FALSE то будет следить за переполнением принимающего буфера.
		dcb.fNull = TRUE;
		dcb.StopBits = ONESTOPBIT;

		/*EFlowControl fc;
		switch (fc)
		{
			case ENoFlowControl: // No HandShaking
			{
				dcb.fOutxCtsFlow = FALSE; // Disable CTS(Clear To Send) monitoring
				dcb.fOutxDsrFlow = FALSE; // Disable DSR(Data Set Ready) monitoring
				dcb.fDtrControl = DTR_CONTROL_DISABLE; //Сигнал  DTR (готовности терминала к передаче данных)  управления потоком данных. Этот член структуры может быть одним из следующих значений.
				//DTR_CONTROL_ENABLE	Включает линию DTR, когда устройство открывается и оставляет ее включенной.
				//DTR_CONTROL_HANDSHAKE	Отключает линию DTR, когда устройство открывается и оставляет ее заблокированной.
				//DTR_CONTROL_DISABLE	Включает  процедуру установления связи DTR. Если процедура установления связи включена, она является ошибкой для приложения, которое корректировать линию, используя функцию EscapeCommFunction.

				dcb.fRtsControl = RTS_CONTROL_DISABLE; // Disable RTS (Ready To Send) monitoring
				dcb.fOutX = FALSE; // Disable XON/XOFF for transmission (Управление потоком (это своойство есть в гипертерминале))
				dcb.fInX = FALSE; // Disable XON/XOFF for receiving
				break;
			}
			case EXonXoffFlowControl: // Software Handshaking
			{
				dcb.fOutxCtsFlow = FALSE;
				dcb.fOutxDsrFlow = FALSE;
				dcb.fDtrControl = DTR_CONTROL_DISABLE;
				dcb.fRtsControl = RTS_CONTROL_DISABLE;
				dcb.fOutX = TRUE;
				dcb.fInX = TRUE;
				dcb.XonChar = 0x11;
				dcb.XoffChar = 0x13;
				dcb.XoffLim = 100;
				dcb.XonLim = 100;
				break;
			}
			case EFullHardwareFlowControl: // Hardware Handshaking
			{*/
				dcb.fOutxCtsFlow = TRUE;
				dcb.fOutxDsrFlow = TRUE;
				dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
				dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
				dcb.fOutX = FALSE;
				dcb.fInX = FALSE;
			/*}
			case ECtsRtsFlowControl:
			{
				dcb.fOutxCtsFlow = TRUE;
				dcb.fOutxDsrFlow = FALSE;
				dcb.fDtrControl = DTR_CONTROL_DISABLE;
				dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
				dcb.fOutX = FALSE;
				dcb.fInX = FALSE;
				break;
			}
			case ECtsDtrFlowControl:
			{
				dcb.fOutxCtsFlow = TRUE;
				dcb.fOutxDsrFlow = FALSE;
				dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
				dcb.fRtsControl = RTS_CONTROL_DISABLE;
				dcb.fOutX = FALSE;
				dcb.fInX = FALSE;
				break;
			}
			case EDsrRtsFlowControl:
			{
				dcb.fOutxCtsFlow = FALSE;
				dcb.fOutxDsrFlow = TRUE;
				dcb.fDtrControl = DTR_CONTROL_DISABLE;
				dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
				dcb.fOutX = FALSE;
				dcb.fInX = FALSE;
				break;
			}
			case EDsrDtrFlowControl:
			{
				dcb.fOutxCtsFlow = FALSE;
				dcb.fOutxDsrFlow = TRUE;
				dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
				dcb.fRtsControl = RTS_CONTROL_DISABLE;
				dcb.fOutX = FALSE;
				dcb.fInX = FALSE;
				break;
			}
			default:
			{
				RETAILMSG(1,(_T("CSerial::Setup - %s flow control assigned
				Failed!!"), sPort));
				return;
			}
		}*/
	}
	if(!SetCommState(hCom, &dcb)) return false;

	//Заебался и по умолчанию сделал асинхронно (операция чтени Read не ждёт данные и за временем нужно следить самому).
	if(!SetTimeout(m_time)) return false;

	return true;
}
//------------------------------------------------------------------------------
//Сколько ждать данных в миллисекундах (Для чтения и запииси)
//Операция чтения работает асинхронно те. не ждёт данные за временем нужно следить самому ! (читать байты в цикле с задержкой)
bool ComPort::SetTimeout(unsigned long time)
{
	m_time=time;
	COMMTIMEOUTS CommTimeouts;
/*	CommTimeouts.ReadIntervalTimeout = MAXDWORD; //Максимальное время, которое допускается для интервала между поступлением двух символов
	CommTimeouts.ReadTotalTimeoutMultiplier  = 0; //Множитель умножается на число проч. байтов получаются милисекунды которые прибовляются к нижнему
	CommTimeouts.ReadTotalTimeoutConstant    = time; //Это время простоя прибавляется к (ReadTotalTimeoutMultiplier * кол-во прочитанных байт)
	CommTimeouts.WriteTotalTimeoutMultiplier = 0; //Множитель умножается на число зап. байтов получаются милисекунды которые прибовляются к нижнему
	CommTimeouts.WriteTotalTimeoutConstant   = time; //Это время простоя для записи прибавляется к (WriteTotalTimeoutMultiplier * кол-во записанных байт)
*/
	CommTimeouts.ReadIntervalTimeout = 400;
	CommTimeouts.ReadTotalTimeoutMultiplier  = 0;
	CommTimeouts.ReadTotalTimeoutConstant    = 400;
	CommTimeouts.WriteTotalTimeoutMultiplier = 0;
	CommTimeouts.WriteTotalTimeoutConstant   = 400;
        
	return SetCommTimeouts(hCom, &CommTimeouts)!=0; //В MSDN так написанно
}
//------------------------------------------------------------------------------
/*bool ComPort::setBaudRate()
{	CheckBaudRate(); //Чтоб скорость была в

	//TDCB dcb;
	DCB dcb;
	if(!GetCommState(hCom, &dcb)) return false;
	dcb.BaudRate=BaudRate;
	dcb.ByteSize=8;
	dcb.Parity=NOPARITY;
	dcb.StopBits=ONESTOPBIT;
//	dcb.Flags=DTR_CONTROL_ENABLE;
	dcb.fDtrControl=DTR_CONTROL_ENABLE;
	if(!SetCommState(hCom, &dcb)) return false;
	return true;
}*/
//------------------------------------------------------------------------------
//Записать буфер в COM порт
unsigned long ComPort::Write(const void* lpBuffer,unsigned long nNumberOfBytesToWrite)
{
	unsigned long lpNumberOfBytesWritten;
	WriteFile(hCom, lpBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL);
	return lpNumberOfBytesWritten;
}
//------------------------------------------------------------------------------
//Записать строку в COM порт
unsigned long ComPort::WriteString(std::string str)
{
	return Write(str.c_str(),str.length());
}
//------------------------------------------------------------------------------
//Записать 1 байт в COM порт
char ComPort::WriteChar(char ch)
{
	return (char)Write(&ch,1);
}
//------------------------------------------------------------------------------
//Прочитать байты из COM порта в буфер
unsigned long ComPort::Read(void* lpBuffer,unsigned long nNumberOfBytesToRead)
{
	unsigned long lpNumberOfBytesRead;
	ReadFile(hCom, lpBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL);
	if(nNumberOfBytesToRead>255) throw "(ComPort::Read) Переполнение буфера!";
	return lpNumberOfBytesRead;
}
//------------------------------------------------------------------------------
