// ClassCOM.cpp: определяет точку входа для консольного приложения.
//

#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <process.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';
}

unsigned __stdcall ReadThread(void *);  //поток чтения
unsigned __stdcall WINAPI WriteThread(void *); //поток записи

class ClassCOM
{
public:
	struct Data_Port
{
	OVERLAPPED overlapped;
	HANDLE COMport;
	int  counter;
	char *buffer;
	bool flag;      //флаг чтения/записи
	HANDLE hEvent;
};
	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;
	 HANDLE reader,writer; //дескрипторы потоков
	 bool state; //флаг открытия порта
	 char buffer_read[1000]; //буфер приема
	 char buffer_write[1000]; //буфер передачи
	 Data_Port read;
	 Data_Port write;
	 
	 HANDLE hEvent_read; // решение критических зон для чтения
	 HANDLE hEvent_write; // решение критических зон для записи

};

ClassCOM :: ClassCOM()
{
	COMport = NULL;
	reader = NULL;
	writer = NULL;
	state = false;     //флаг открытия порта
	
	hEvent_read =  NULL;
	hEvent_write =  NULL;
}

ClassCOM :: ~ClassCOM()
{
	if(writer)
	{
		TerminateThread(writer,0);
		CloseHandle(write.overlapped.hEvent);	//нужно закрыть объект-событие
		CloseHandle(writer);
		writer = NULL;
	}
	if(reader)
	{
		TerminateThread(reader,0);
		CloseHandle(read.overlapped.hEvent);	//нужно закрыть объект-событие
		CloseHandle(reader);
		reader = NULL;
	}
	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;
	dcb.fOutxDsrFlow = FALSE; 
	dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; 
	dcb.fDsrSensitivity = FALSE; 
	dcb.fNull = FALSE; 
	dcb.fRtsControl = RTS_CONTROL_DISABLE; 
	dcb.fAbortOnError = FALSE; 
	dcb.ByteSize = 8; 
	dcb.Parity = NOPARITY; 
	dcb.StopBits = ONESTOPBIT ; 

	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, false, true, NULL); // автосброс
	hEvent_write = CreateEvent(NULL, false, true, NULL); // автосброс

	//*************************************************

	ZeroMemory(&read,sizeof(read));

	 read.overlapped.hEvent = CreateEvent(NULL, true, true, NULL); // создать сигнальный объект-событие
							  // для асинхронных операций
	 read.COMport = COMport;
	 read.counter = 0;
	 read.buffer = buffer_read;
	 read.flag = false; 
	 read.hEvent = hEvent_read; 

	  //*************************************************

	  ZeroMemory(&write,sizeof(write));

	 write.overlapped.hEvent = CreateEvent(NULL, true, true, NULL); // создать сигнальный объект-событие
							  // для асинхронных операций
	 write.COMport = COMport;
	 write.counter = 0;
	 write.buffer = buffer_write;
	 write.flag = false; 
	 write.hEvent = hEvent_write; 

	 //создаем потоки чтения/записи
	 
	 reader = (HANDLE)_beginthreadex(NULL, 0, ReadThread, &read, 0, NULL); //поток чтения
	 writer = (HANDLE)_beginthreadex(NULL, 0, WriteThread, &write, 0, NULL); //поток записи

	 if (!reader || !writer) return false;
	 
	 state = true;  //установить флаг открытия порта
  
   return true;
  }  

void ClassCOM :: CloseCom()
{
	if(writer)
	{
		TerminateThread(writer,0);
		CloseHandle(write.overlapped.hEvent);	//нужно закрыть объект-событие
		CloseHandle(writer);
		writer = NULL;
	}
	if(reader)
	{
		TerminateThread(reader,0);
		CloseHandle(read.overlapped.hEvent);	//нужно закрыть объект-событие
		CloseHandle(reader);
		reader = NULL;
	}
	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;

	WaitForSingleObject(hEvent_write, INFINITE); //начало критического участка

	  bool flag_write = write.flag;

	  if (!flag_write && buff && (szBuff > 0))
	  {
		  strcpy(buffer_write,buff,szBuff);
		  
		  write.flag = true;      //установить флаг записи
		  write.counter = szBuff; //установить байты записи
		  
		  SetEvent(hEvent_write); //конец критического участка
		  return true;
	  }
	  else
	  {
		  SetEvent(hEvent_write); //конец критического участка
		  return false;
	  }
}


bool ClassCOM :: ReadCom(char* buff, int szBuff)
{
	if (!state)  return false;
	
	WaitForSingleObject(hEvent_read, INFINITE); //начало критического участка

	bool flag_read = read.flag;
	

	 if (flag_read && (szBuff > 0) && (szBuff <= 100))
	 {
		 strcpy(buff,buffer_read,szBuff);
		 
		 read.flag = false; //сбросить флаг чтения
		 
		 SetEvent(hEvent_read); //конец критического участка
		 return true;
	 
	 }
	  else
	  {
		  SetEvent(hEvent_read); //конец критического участка
		  return false;
	  }
}



int main()
{
	
	return 0;
}

unsigned __stdcall ReadThread(void *lpParam)
{
	ClassCOM::Data_Port &data = *(ClassCOM::Data_Port *)lpParam; //получить ссылку на структуру Data_Port

	OVERLAPPED &overlapped = data.overlapped;
	HANDLE COMport = data.COMport;
	char *buffer_read = data.buffer; 
	char *buffer = buffer_read; 
	HANDLE hEvent = data.hEvent;

	int counter = 0;

	COMSTAT comstat;		
	DWORD btr, temp, mask, signal;	
	
	SetCommMask(COMport, EV_RXCHAR);  //установить маску        
	
	while(1)				    
	{
		WaitCommEvent(COMport, &mask, &overlapped);               	
		
		signal = WaitForSingleObject(overlapped.hEvent, INFINITE);	
		
		if(signal == WAIT_OBJECT_0)				       
		{
			if(GetOverlappedResult(COMport, &overlapped, &temp, true))
				if((mask & EV_RXCHAR)!=0)					
				{
					ClearCommError(COMport, &temp, &comstat);		
					btr = comstat.cbInQue;                          	
					if(btr)                         			
					{
						ReadFile(COMport, buffer, btr, &temp, &overlapped);     //прочитать байты из порта в буфер программы
						
						signal = WaitForSingleObject(overlapped.hEvent, INFINITE);
						
						if((signal == WAIT_OBJECT_0) && (GetOverlappedResult(COMport, &overlapped, &temp, true)))
						{
							counter+=btr; //увеличиваем счётчик байтов 
							buffer+=btr;  //переместить указатель  
							
							if (counter >= 100) 
							{
								WaitForSingleObject(hEvent, INFINITE); //начало критического участка
								
								data.flag = true; //установить флаг чтения
								
								SetEvent(hEvent); //конец критического участка
								
								buffer = buffer_read;  //переместить указатель на начало
								counter = 0;           //сбросить счётчик байтов 
							}
						}
					}
				}
		}
	}
}


unsigned __stdcall WriteThread(void *lpParam)
{
	ClassCOM::Data_Port &data = *(ClassCOM::Data_Port *)lpParam; //получить ссылку на структуру Data_Port
	
	DWORD temp, signal;	
	bool flag_write; //флаг записи
	int counter;
	
	OVERLAPPED &overlapped = data.overlapped;
	HANDLE COMport = data.COMport;

	char *buffer_write = data.buffer;

	HANDLE hEvent = data.hEvent;
	
	while(1)
	{
		WaitForSingleObject(hEvent, INFINITE); //начало критического участка
		
		flag_write = data.flag;
		counter = data.counter;  //к-во байт записи
		
		SetEvent(hEvent); //конец критического участка
		
		if (flag_write)
		{
			WriteFile(COMport, buffer_write, counter, &temp, &overlapped); //записать байты из буфера программы в порт
			
			signal = WaitForSingleObject(overlapped.hEvent, INFINITE);
			
			if((signal == WAIT_OBJECT_0) && (GetOverlappedResult(COMport, &overlapped, &temp, true)))
			{
				WaitForSingleObject(hEvent, INFINITE); //начало критического участка
				
				data.flag = false; //сбросить флаг записи
				
				SetEvent(hEvent); //конец критического участка
			}
		}
	}
}