•
Продукты • Где купить • Пользователям • Для бизнеса • Мы на связи |
null null null
|
API для работы с устройствами IRLink серии VS Это первая версия описания программного интерфейса для работы с нашими устройствами. Если у вас возникнут вопросы, пожалуйста, свяжитесь с нами. Данное API предназначено для работы с устройствами IRLink серии VS: приёмникам и приёмниками-излучателями (тип корпуса при этом значения не имеет). Статья про кодировки пультов ДУ. После установки драйверов IRLink.VS в системе появляется виртуальный COM порт. Для работы с устройством надо открыть появившийся порт и протестировать наличие устройства на нём (т. к. виртуальные COM порты могут использоваться также Bluetooth адаптерами, GPRS навигаторами и пр.). Для опознания приёмника надо записать в порт байт 0x81, в ответ придёт такой же. Для опознания излучателя используется байт 0x82. Для приёмника-излучателя надо использовать оба байта последовательно. Обратите внимание, что опознание устройства происходит по тому же каналу, что и приём данных, то есть гипотеически возможно получить ответный байт не как реакцию устройства на запрос, а просто выловить ответный байт в поток данных, посылаемых устройствов в порт. При приёме сигналов приёмник записывает в порт последовательность импульсов и пауз в сигнале после принятия сигнала (то есть по истечении максимально возможной кодируемой паузы). Каждый байт в посылке обозначает импульс или паузу и данные о масштабе.
Например ИК импульс длительностью 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(), который делает следующее: если встречается слишком маленькая пауза, то она не засчитывается за паузу, а считается как продолжение предыдущего импульса. Примеры
Пример тестиров для приёмника и излучателя |
Главная l Продукты | Где купить | Пользователям | Предложения для бизнеса | Мы на связи | Мешки-сетки для хранения спальников |
|