#linux #usb #polling #hid #write
#c #linux #usb #опрос #hid
Вопрос:
У нас есть набор USB-устройств, которые мы отслеживаем с помощью RPi. Код мониторинга опрашивает устройства, использующие интерфейс hidraw direct, примерно раз в секунду. Протокол использует 64-байтовые пакеты для отправки команд и получения данных, и все ответы имеют длину не более 64 байт.
Та же схема отлично работает под Windows с использованием драйвера Windows HID. Однако в Linux мы используем hidraw и обнаруживаем, что интерфейс устройства через короткое время заклинивается, что приводит к неудачной записи {} на устройство.
После долгих исследований я наткнулся на рекомендацию попытаться отслеживать связь между хостом и устройством hidraw, используя это в терминале:
sudo cat /dev/hidraw0
Как выясняется, выполнение этой команды выводит на терминал 4-8 байт нечитаемых символов каждый write()
, и неожиданно это также устраняет замятие hidraw0
. Все последующие write()
‘s и read()
‘s для этого устройства работают безупречно.
Если это устройство отключено, а затем повторно подключено, состояние замятия возвращается вскоре после этого. Я сделал один шаг кода и проверил, что «мусор» выводится во время выполнения write()
.
Я пытался добавлять fsync()
вызовы до и после write()
в надежде очистить буферы и избежать этой проблемы, но это не помогло. Код для write()
и последующих read()
является стандартным следующим образом:
#define USB_PACKET 64
#define USB_WRDELAY 10 //ms
FILE* fd;
int errno, res;
char packet[USB_PACKET];
fd = 0;
/* Open the Device with non-blocking reads. */
fd = open("/dev/hidraw0", O_RDWR|O_NONBLOCK);
if (fd < 0) {
perror("Unable to open device");
return 0; // failure
}
memset(packet, 0x0, sizeof(packet));
packet[0] = 0x34; // command code - request for USB device status bytes
fsync();
res = write(fd, amp;packet, sizeof(packet));
fsync();
if (res < 0) {
printf("Error: %d in USB write()n", errno);
close(fd);
return 0; // failure
} else {
usleep(1000*USB_WRDELAY ); // delay gives OS and device time to respond
res = read(fd, amp;packet, sizeof(packet));
if (res < 0) {
printf("Error: %d in USB read()n", errno);
close(fd);
return 0; // failure
} else {
// good read, packet holds the response data
// process the device data
close(fd);
return 1; // OK
}
}
return 0; // failure
Это пример тарабарщины, которую мы читаем на терминале, выполняющем cat
команду для каждого выполняемого write()
:
4n��@/5 �
Я не понимаю, откуда берется этот мусор и как от него избавиться. Я попробовал несколько вещей, которые не сработали, например, добавление a read()
с таймаутом перед записью — надеясь, что это какие-то данные, оставшиеся от предыдущего неполного read()
.
Также пытался записать буфер меньшего размера, так как мне нужно отправить только 2-байтовую команду, а также добавить задержку между open()
и write()
.
К сожалению, использование cat в терминале мешает обнаружению USB-устройств при горячем подключении / отключении, поэтому это не решение, которое мы можем использовать при развертывании.
Я буду признателен за любые мудрые слова по этому поводу.