//
// Этот тест производит поиск приёмника IRLink и начинает принимать с него сигналы
//

#include "stdafx.h"
#include <time.h>
#include <math.h>

BOOL checkDevice(const char* portName, char* portDescription);

int main(){
	char* portName = NULL;

	//перечисление по реестру установленных в системе COM портов
	//и поиск на каждом из них устройства IRLink

	HKEY hKey;
	LONG result;
	
	result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
		"HARDWARE\\DEVICEMAP\\SERIALCOMM",
		0, 
		KEY_ALL_ACCESS, 
		&hKey);

	if(result != ERROR_SUCCESS){
		MessageBox(NULL, "error opening registry", "IRLink", MB_OK);
	}

	// для работы с COM портом требуется закрыть другие программы,
	// которые могут его использовать
	printf("Please shut down IRLink.3 and IRLink.Lite.\nDetecting IRLink.VS on different COM ports:\n");

	DWORD portCount = -1;
	DWORD keyNameSize = 16, keyValueSize = 8;
    char *keyName = (char *)malloc(keyNameSize);
	char *portName2 = (char *)malloc(keyValueSize);
	do{
		portCount ++;
		//
		//after each reading (RegQueryValueEx) of a registry value buffersizeentry is changed to the size of last read number of bytes. So you should set again this value before using it in a new RegQueryValueEx 
		//
		keyNameSize = 16;
		keyValueSize = 8;
		result = RegEnumValue(hKey, portCount, keyName, &keyNameSize, NULL, NULL, (LPBYTE)portName2, &keyValueSize);
		if(result == ERROR_SUCCESS){
			BOOL portResult = checkDevice(portName2, keyName);
			if(portResult){
				printf("%s -- OK, device detected =|:-)=\n", portName2);
			}else{
				printf("%s -- failed to detect device :(\n", portName2);			
			}
			if(result == ERROR_SUCCESS && portResult){
				portName = portName2;
			}
			SecureZeroMemory(keyName, keyNameSize);
		}
	}while(result != ERROR_NO_MORE_ITEMS && portName == NULL);
	RegCloseKey(hKey);
	
	if(portName == NULL){
		Sleep(10000);
		return 1;
	}

	// устройство обнаружено, читаем сигнал с пульта
	printf("Listening codes on port %s, press any key on remote control:\n", portName);

	HANDLE hComm;
	char buff[128] = "\\\\.\\";
	StrCat(buff, portName);
	hComm = CreateFile( buff,  
						GENERIC_READ | GENERIC_WRITE, 
						0, 
						0, 
						OPEN_EXISTING,
						NULL,
						0);

	if(hComm == INVALID_HANDLE_VALUE){
		return 1;
	}

	DCB dcb;
    GetCommState(hComm, &dcb);

	dcb.BaudRate = CBR_115200;
	dcb.ByteSize = 8;
	dcb.StopBits = ONESTOPBIT;
	dcb.fRtsControl = RTS_CONTROL_DISABLE;
	dcb.fDtrControl = DTR_CONTROL_DISABLE;

	SetCommState(hComm, &dcb);
	
	COMMTIMEOUTS timeouts;
	GetCommTimeouts(hComm, &timeouts);
	timeouts.ReadIntervalTimeout = 1;
	timeouts.ReadTotalTimeoutConstant = 1;
	timeouts.ReadTotalTimeoutMultiplier = 0;
	timeouts.WriteTotalTimeoutConstant = 10;
	timeouts.WriteTotalTimeoutMultiplier = 0;
	SetCommTimeouts(hComm, &timeouts);

	BYTE byte;
	DWORD bytesRead;
	
	while(true){
		// обратите внимание, что здесь не производится расшифровка сигнала:
		// не выделяются импульсы и паузы, не применяется машстаб

		if(!ReadFile (hComm, &byte, 1, &bytesRead, NULL) || bytesRead != 1){	
			continue;
		}
		printf("%d ", byte);
		if(byte > 250){
			printf("\n");
		}
	}
	CloseHandle(hComm);
	return 1;		
}

BOOL checkDevice(const char* portName, char* portDescription){
	if(StrStrI(portDescription, "vcp") == NULL){
		return FALSE;
	}
	HANDLE hComm;
	char buff[128] = "\\\\.\\";
	StrCat(buff, portName);
	hComm = CreateFile( buff,  
						GENERIC_READ | GENERIC_WRITE, 
						0, 
						0, 
						OPEN_EXISTING,
						FILE_FLAG_OVERLAPPED,
						0);
	if(hComm == NULL){
		printf("errorr!!!!!!!!!!!!!!!! in opening port!\n");
	}

	DCB dcb;
	GetCommState(hComm, &dcb);
	dcb.BaudRate = CBR_115200;
	dcb.ByteSize = 8;
	dcb.StopBits = ONESTOPBIT;
	dcb.fParity = 0;
	dcb.fRtsControl = RTS_CONTROL_DISABLE;
	dcb.fDtrControl = DTR_CONTROL_DISABLE;

	dcb.DCBlength=sizeof(DCB);
	
	SetCommState(hComm, &dcb);

	COMMTIMEOUTS timeouts;
	GetCommTimeouts(hComm, &timeouts);
	timeouts.ReadIntervalTimeout = 1;
	timeouts.ReadTotalTimeoutConstant = 1;
	timeouts.ReadTotalTimeoutMultiplier = 0;
	timeouts.WriteTotalTimeoutConstant = 10;
	timeouts.WriteTotalTimeoutMultiplier = 0;
	SetCommTimeouts(hComm, &timeouts);

	Sleep(200);

	OVERLAPPED o = {0};
	o.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

	// приёмнк отвечает на отправленный в порт байт 0x81 байтом 0x81

	const BYTE TEST_BYTE  = 0x81;
	byte TEST_ARR[] = {0, 0x81};
	DWORD bytesCount;

	WriteFile(hComm, &TEST_ARR[0], 2, &bytesCount, &o);
	DWORD error = GetLastError();
	if(error ==  ERROR_IO_PENDING){
		DWORD result = WaitForSingleObject(o.hEvent, 200);
		if(result == WAIT_OBJECT_0){
			//printf("all bytes should be wrtitted, ");
		}
	}else{
		printf("err 22: \n", GetLastError());
		CloseHandle(hComm);
		CloseHandle(o.hEvent);
		return false;
	}
	
	Sleep(70);

	BYTE receivedByte[128] = {0};
	ReadFile(hComm, &receivedByte[0], 128, &bytesCount, &o);
	error = GetLastError();
	if(error == ERROR_IO_PENDING){
		DWORD result = WaitForSingleObject(o.hEvent, 200);
		if(result == WAIT_TIMEOUT){
			CloseHandle(o.hEvent);
			CloseHandle(hComm);
			return FALSE;
		}else if(result == WAIT_OBJECT_0){
			BOOL replyFound = false;
			for(int i=0; i<128 && !replyFound; i++){
				//printf("%d ", receivedByte[i]);
				replyFound = (receivedByte[i] == 0x81);
			}
			//printf("\n");
			CloseHandle(o.hEvent);
			CloseHandle(hComm);
			return replyFound;
		}
	}else{
		CloseHandle(o.hEvent);
		CloseHandle(hComm);
		return FALSE;
	}
}
