Продукты
 Где купить
 Пользователям
 Для бизнеса
 Мы на связи

   

Меню раздела

Главная раздела
Скачать программы
Подписка на новости
Проблемы с устройством

Программа IRlink

Скачать свежую версию  3.736 (2010/02/06 04:19:21)


Поддержка Vista

Программа и устройства IRLink поддерживают Vista.


Управление техникой с компьютера

Приёмо-излучатель Радиалис позволяет управлять бытовой техникой с компьютера.


Поддержка MediaCenter и x64

IRLink позволяет управлять Windows MediaCenter с любого пульта ДУ.


API для работы с устройствами IRLink серии VS

Это первая версия описания программного интерфейса для работы с нашими устройствами. Если у вас возникнут вопросы, пожалуйста, свяжитесь с нами.

Данное API предназначено для работы с устройствами IRLink серии VS: приёмникам и приёмниками-излучателями (тип корпуса при этом значения не имеет).

Статья про кодировки пультов ДУ.

После установки драйверов IRLink.VS в системе появляется виртуальный COM порт. Для работы с устройством надо открыть появившийся порт и протестировать наличие устройства на нём (т. к. виртуальные COM порты могут использоваться также Bluetooth адаптерами, GPRS навигаторами и пр.). Для опознания приёмника надо записать в порт байт 0x81, в ответ придёт такой же. Для опознания излучателя используется байт 0x82. Для приёмника-излучателя надо использовать оба байта последовательно. Обратите внимание, что опознание устройства происходит по тому же каналу, что и приём данных, то есть гипотеически возможно получить ответный байт не как реакцию устройства на запрос, а просто выловить ответный байт в поток данных, посылаемых устройствов в порт.

При приёме сигналов приёмник записывает в порт последовательность импульсов и пауз в сигнале после принятия сигнала (то есть по истечении максимально возможной кодируемой паузы). Каждый байт в посылке обозначает импульс или паузу и данные о масштабе.

Номер бита в байте 7 (старший) 6 5 4 3 2 1 0 (младший)
Назначение Масштаб времени «0» = 1/14400 сек, «1» = 1/3600 сек. Промежуток времени «1» – ИК импульс, «0» - пауза.

Например ИК импульс длительностью 8,9 мс будет обозначаться байтом 0xC1, а пауза длительностью 4,4 мс будет обозначаться байтом 0xA0. ИК импульс, длительностью 417 мкс будет обозначаться 0x0E. ИК импульс длительностью более 256/14400 обозначается 0xFF. ИК пауза длительностью более 256/14400 обозначается 0xFE. При работе с излучателем когда есть возможность представить один и тот же промежуток времени в обих масштабах, предпочтительнее масштаб 1/14400.

Пример поиска устройства


char* findDevice(){
	
	char* portName = NULL;

	HKEY hKey;
	LONG result;

	// перечисление установленных в системе COM портов

	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);
	}

	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);
		//shouldnt check result for ERROR_SUCCESS, because sometime
		//we get ERROR_UNSUFFICIENT_BUFFER_SIZE for keyName
		//we ignore this error because we arent interested in keyName
		if(result != ERROR_NO_MORE_ITEMS && checkDevice(portName2, keyName)){
			portName = portName2;
		}
		SecureZeroMemory(keyName, keyNameSize);
	}while(result != ERROR_NO_MORE_ITEMS && portName == NULL);
	RegCloseKey(hKey);
	return getJString(env, portName);
}

//метод для поиска устройства на заданном порту

BOOL checkDevice(const char* portName, char* portDescription){
	
	// описание виртуального COM порта для IRLink.VS состоит из букв vcp
	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){
		return false;
	}
		
	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;

	SetCommState(hComm, &dcb);

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

	Sleep(100);

	//creating event
	OVERLAPPED o;
	o.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	
	// тестовый байт для проверки устройства
	
	const BYTE TEST_BYTE[]  = {0, 0x81};
	DWORD bytesCount;

	WriteFile(hComm, &TEST_BYTE[0], 2, &bytesCount, &o);
	DWORD error = GetLastError();
	if(error ==  ERROR_IO_PENDING){
		DWORD result = WaitForSingleObject(o.hEvent, 50);
		if(result == WAIT_TIMEOUT){
			CloseHandle(hComm);
			return FALSE;
		}
	}else{
		CloseHandle(hComm);
		return FALSE;
	}

	Sleep(50);

	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(hComm);
			return FALSE;
		}else{
			BOOL replyFound = false;
			for(int i=0; i<128 && !replyFound; i++){
				replyFound = (receivedByte[i] == 0x81);
			}
			CloseHandle(hComm);
			return replyFound;
		}
	}else{
		CloseHandle(hComm);
		return FALSE;
	}
}


Пример чтения данных с приёмника

void run(char* port){


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

	if(hComm == INVALID_HANDLE_VALUE){
		return;
	}

	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);

	Sleep(20);

	DWORD rawBuffer[256] = {0};
	DWORD rawBufferSize = 0;

	DWORD period;
	BYTE byte;
	double value;
	DWORD bytesRead;
	BOOL isPause;

	while(true){
		
		if(!ReadFile (hComm, &byte, 1, &bytesRead, NULL) || bytesRead != 1){	
			continue;
		}

		isPause = !(byte & 1);

		// определение масштаба интервала времени
		if((byte & 128) == 128){
			byte = (byte & 126) >> 1;
			value = byte/0.0000853/3600;
			if(value - floor(value) >= 0.5){
				period = ceil(value);
			}else{
				period = floor(value);
			}
		}else{
			byte = (byte & 126) >> 1;
			value = byte/0.0000853/14400;
			if(value - floor(value) >= 0.5){
				period = ceil(value);
			}else{
				period = floor(value);
			}
		}

		if(period > 200 && isPause){
			// если байт кодирует паузу больше максимально возможной длительнсти — значит это конец посылки

			// теперь у нас в буфере rawBuffer[0] записано rawBufferSize данных об импульсах и паузах.
			// тут делает дальнейшая обработка сигнала

			// очишаем буфер для следующей посылки
			rawBufferSize = 0;
			SecureZeroMemory(&rawBuffer[0], 256*sizeof(DWORD));
		}else{
			if(rawBufferSize < 256){
				rawBuffer[rawBufferSize] = period;
				rawBufferSize++;
			}
		}
	}
	CloseHandle(hComm);
}


Дополнительно

Надо обратить внимание на то, что сигнал у пульта неидеальный, обычно каждые импульс и пауза гуляет немного. Поэтому при сравнении принятого сигнала с образцом имеет смысл делать допуск на каждый импульс и паузу.

При приёме сигнала иногда вместо одного импульса приходит серия более мелких импульсов, разделённых паразитными паузами. В плагине приёмнка IRLink.VS (см. пример ниже) введён дополнительный метод doFiltering(), который делает следующее: если встречается слишком маленькая пауза, то она не засчитывается за паузу, а считается как продолжение предыдущего импульса.

Примеры

Пример тестиров для приёмника и излучателя
Часть кода для приёмника IRLink.VS

Главная l Продукты | Где купить | Пользователям | Предложения для бизнеса | Мы на связи
© 2003–2010 автор идеи Павел Чернорук