// ClassCOM.cpp: определяет точку входа для консольного приложения.
//

#include "stdafx.h"
#include <iostream>
#include <windows.h>

#include "WRITE.h"

using namespace std;

void strcpy(char *buffer_write, const char *buff, int szBuff)
{
	int i;
	for (i=0; i<szBuff; i++) buffer_write[i] = buff[i];
	buffer_write[i] = '\0';
}

class ClassCOM
{
public:
	ClassCOM();
	~ClassCOM();
	bool OpenCom(int port, int baud);	//открыть порт
	bool ReadCom(char* buff, int szBuff); //получить посылку
	bool WriteCom(const char* buff, int szBuff); //отправить посылку
	void CloseCom();
private:
	 HANDLE COMport;
	 
	 bool state; //флаг открытия порта
	 char buffer_read[1000]; //буфер приема
	 char buffer_write[1000]; //буфер передачи
	 OVERLAPPED read;
	 OVERLAPPED write;
	
	 HANDLE hEvent_read; // 
	 HANDLE hEvent_write; // 

};

ClassCOM :: ClassCOM()
{
	COMport = NULL;
	state = false;     //флаг открытия порта
	hEvent_read =  NULL;
	hEvent_write =  NULL;
}

ClassCOM :: ~ClassCOM()
{
	if (hEvent_write)
	{
		CloseHandle(hEvent_write);
		hEvent_write = NULL;
	}
	if (hEvent_read)
	{
		CloseHandle(hEvent_read);
		hEvent_read = NULL;
	}
	if (COMport)
	{
		CloseHandle(COMport);
		COMport = NULL;
	}
	state = false;      //сбросить флаг открытия порта
}

bool ClassCOM :: OpenCom(int port, int baud) //открыть порт
{
	if (state) return true;

	char COM_string[20];
	sprintf(COM_string,"COM%d", port);

	COMport = CreateFile(COM_string,GENERIC_READ | GENERIC_WRITE, 0,
		      NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
	
	if(COMport == INVALID_HANDLE_VALUE) return false;

	DCB dcb;

	GetCommState(COMport, &dcb);

	dcb.DCBlength = sizeof(DCB); //Длина структуры, в байтах.
	dcb.BaudRate = baud; //Скорость передачи данных
	dcb.fBinary = TRUE;  //включаем двоичный режим обмена
	dcb.fOutxCtsFlow = FALSE; //выключаем режим слежения за сигналом CTS
	dcb.fOutxDsrFlow = FALSE; //выключаем режим слежения за сигналом DSR
	dcb.fDtrControl = DTR_CONTROL_DISABLE; //отключаем использование линии DTR 
	dcb.fDsrSensitivity = FALSE; //отключаем восприимчивость драйвера к состоянию линии DSR
	dcb.fNull = FALSE; //разрешить приём нулевых байтов
	dcb.fRtsControl = RTS_CONTROL_DISABLE; //отключаем использование линии RTS
	dcb.fAbortOnError = FALSE; //отключаем остановку всех операций чтения/записи при ошибке
	dcb.ByteSize = 8; //Число переданных и принятых битов, в байтах.
	dcb.Parity = NOPARITY; //Без проверки четности
	dcb.StopBits = ONESTOPBIT; //1 стоповый бит 

	SetCommState(COMport, &dcb);

	COMMTIMEOUTS timeouts;

	 timeouts.ReadIntervalTimeout = 0;	 	
	 timeouts.ReadTotalTimeoutMultiplier = 0;	
	 timeouts.ReadTotalTimeoutConstant = 0;   
	 timeouts.WriteTotalTimeoutMultiplier = 0;    
	 timeouts.WriteTotalTimeoutConstant = 0;  

	 SetCommTimeouts(COMport, &timeouts);

	 SetupComm(COMport, 1000, 1000);

	 PurgeComm(COMport, PURGE_RXCLEAR); 

	 //*************************************************

	hEvent_read = CreateEvent(NULL, true, true, NULL); // ручной сброс
	hEvent_write = CreateEvent(NULL, true, true, NULL); // ручной сброс

	//*************************************************

	ZeroMemory(&read,sizeof(read));

	 read.hEvent = hEvent_read; // создать сигнальный объект-событие
							    // для асинхронных операций
	 
	  //*************************************************

	  ZeroMemory(&write,sizeof(write));

	 write.hEvent = hEvent_write; // создать сигнальный объект-событие
							  // для асинхронных операций
	 
	 state = true;  //установить флаг открытия порта
  
   return true;
  }  

void ClassCOM :: CloseCom()
{
	if (hEvent_write)
	{
		CloseHandle(hEvent_write);
		hEvent_write = NULL;
	}
	if (hEvent_read)
	{
		CloseHandle(hEvent_read);
		hEvent_read = NULL;
	}
	if (COMport)
	{
		CloseHandle(COMport);
		COMport = NULL;
	}
	state = false;     //сбросить флаг открытия порта
}

bool ClassCOM :: WriteCom(const char* buff, int szBuff)
{
	if (!state)  return false;
	
	DWORD signal,temp;
	
	signal = WaitForSingleObject(hEvent_write, 0);

	if((signal == WAIT_OBJECT_0)) 
	{
		 if (buff && (szBuff > 0))
		 {
			 strcpy(buffer_write,buff,szBuff);
			 
			 WriteFile(COMport, buffer_write, szBuff, &temp, &write);

			 return true;
		 }
		 else  return false;
	}
	else return false;
}


bool ClassCOM :: ReadCom(char* buff, int szBuff)
{
	if (!state)  return false;

	DWORD signal,temp,btr;

	COMSTAT comstat;

	ClearCommError(COMport, &temp, &comstat);	
	
	btr = comstat.cbInQue;  

	if (buff && (szBuff > 0) && (szBuff <= btr))
	{
		ReadFile(COMport, buffer_read, szBuff, &temp, &read); 

		WaitForSingleObject(hEvent_read, INFINITE);

		strcpy(buff,buffer_read,szBuff);

		return true;
	}
	else  return false;
}



int main()
{
	ClassCOM COM;
	if (COM.OpenCom(1, CBR_110)) cout<<"OK 1"<<endl;
	cout<<strlen(write)<<endl;
	system("pause");
	if (COM.WriteCom(write, strlen(write))) cout<<"OK 2"<<endl;
	system("pause");
	while (!COM.ReadCom(read, strlen(write))) {cout<<"OK 3"<<endl;}
	system("pause");
	cout<<read<<endl;
	system("pause");
	cout<<strlen(read)<<endl;
	system("pause");
	cout<<"**********************************"<<endl;
	system("pause");
	if (COM.WriteCom(write, strlen(write))) cout<<"OK 2"<<endl;
	//system("pause");
	while (!COM.ReadCom(read, strlen(write))) {cout<<"OK 3"<<endl;}
	system("pause");
	cout<<read<<endl;
	system("pause");
	cout<<strlen(read)<<endl;
	system("pause");
	return 0;
}

