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

   

Меню раздела

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

Программа IRlink

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


IRLink для PS/2


Получи IRLink бесплатно!

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

Получи IRLink бесплатно


Консультант на дом

Можно вызвыть консультанта на дом, он установит и обучит приёмам работы с IRLink.

Доставка курьером


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 автор идеи Павел