Доступ к данным устройства USB только на основе отчета DESCRIPTOR HID
У меня есть цифровой измеритель уровня звука (сонометр) GM1356 с USB. В Windows есть какое-то программное обеспечение, но у меня нет компакт-диска, и он не доступен в Интернете. Что я хочу сделать, так это прочитать данные о текущем уровне шума в Linux.
Я уже нашел библиотеку, которая позволяет мне делать это на языке, который я знаю (ruby, libusb). На следующем шаге я установил wireshark, чтобы проверить, что он посылает на компьютер. Это не слишком много. Самый интересный пакет, который я нашел, DESCRIPTOR HID Report
, Интересно, какие дальнейшие шаги я должен предпринять, чтобы прочитать данные, которые мне интересны? Как я могу определить, какие запросы я должен отправить, чтобы получить его?
HID Report
Global item (Usage)
Header
.... ..10 = bSize: 2 bytes (2)
.... 01.. = bType: Global (1)
0000 .... = bTag: Usage (0x0)
Usage page: [Vendor-defined] (0xffa0)
Local item (Usage)
Header
.... ..01 = bSize: 1 byte (1)
.... 10.. = bType: Local (2)
0000 .... = bTag: Usage (0x0)
Usage: [Vendor-defined] (0xffa00001)
Main item (Collection)
Header
.... ..01 = bSize: 1 byte (1)
.... 00.. = bType: Main (0)
1010 .... = bTag: Collection (0xa)
Collection type: Application (0x01)
Local item (Usage)
Header
.... ..01 = bSize: 1 byte (1)
.... 10.. = bType: Local (2)
0000 .... = bTag: Usage (0x0)
Usage: [Vendor-defined] (0xffa00002)
Main item (Collection)
Header
.... ..01 = bSize: 1 byte (1)
.... 00.. = bType: Main (0)
1010 .... = bTag: Collection (0xa)
Collection type: Physical (0x00)
Global item (Usage)
Header
.... ..10 = bSize: 2 bytes (2)
.... 01.. = bType: Global (1)
0000 .... = bTag: Usage (0x0)
Usage page: [Vendor-defined] (0xffa1)
Local item (Usage)
Header
.... ..01 = bSize: 1 byte (1)
.... 10.. = bType: Local (2)
0000 .... = bTag: Usage (0x0)
Usage: [Vendor-defined] (0xffa10003)
Local item (Usage)
Header
.... ..01 = bSize: 1 byte (1)
.... 10.. = bType: Local (2)
0000 .... = bTag: Usage (0x0)
Usage: [Vendor-defined] (0xffa10004)
Global item (Logical minimum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0001 .... = bTag: Logical minimum (0x1)
Logical minimum: 128
Global item (Logical maximum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0010 .... = bTag: Logical maximum (0x2)
Logical maximum: 127
Global item (Physical minimum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0011 .... = bTag: Physical minimum (0x3)
Physical minimum: 0
Global item (Physical maximum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0100 .... = bTag: Physical maximum (0x4)
Physical maximum: 255
Global item (Report size)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0111 .... = bTag: Report size (0x7)
Report size: 8
Global item (Report count)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
1001 .... = bTag: Report count (0x9)
Report count: 8
Main item (Input)
Header
.... ..01 = bSize: 1 byte (1)
.... 00.. = bType: Main (0)
1000 .... = bTag: Input (0x8)
.... .... 0 = Data/constant: Data
.... ...1 . = Data type: Variable
.... ..0. . = Coordinates: Absolute
.... .0.. . = Min/max wraparound: No Wrap
.... 0... . = Physical relationship to data: Linear
...0 .... . = Preferred state: Preferred State
..0. .... . = Has null position: No Null position
.0.. .... . = [Reserved]: False
0... .... . = Bits or bytes: Buffered bytes (default, no second byte present)
Local item (Usage)
Header
.... ..01 = bSize: 1 byte (1)
.... 10.. = bType: Local (2)
0000 .... = bTag: Usage (0x0)
Usage: [Vendor-defined] (0xffa10005)
Local item (Usage)
Header
.... ..01 = bSize: 1 byte (1)
.... 10.. = bType: Local (2)
0000 .... = bTag: Usage (0x0)
Usage: [Vendor-defined] (0xffa10006)
Global item (Logical minimum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0001 .... = bTag: Logical minimum (0x1)
Logical minimum: 128
Global item (Logical maximum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0010 .... = bTag: Logical maximum (0x2)
Logical maximum: 127
Global item (Physical minimum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0011 .... = bTag: Physical minimum (0x3)
Physical minimum: 0
Global item (Physical maximum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0100 .... = bTag: Physical maximum (0x4)
Physical maximum: 255
Global item (Report size)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0111 .... = bTag: Report size (0x7)
Report size: 8
Global item (Report count)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
1001 .... = bTag: Report count (0x9)
Report count: 8
Main item (Output)
Header
.... ..01 = bSize: 1 byte (1)
.... 00.. = bType: Main (0)
1001 .... = bTag: Output (0x9)
.... .... 0 = Data/constant: Data
.... ...1 . = Data type: Variable
.... ..0. . = Coordinates: Absolute
.... .0.. . = Min/max wraparound: No Wrap
.... 0... . = Physical relationship to data: Linear
...0 .... . = Preferred state: Preferred State
..0. .... . = Has null position: No Null position
.0.. .... . = (Non)-volatile: Non Volatile
0... .... . = Bits or bytes: Buffered bytes (default, no second byte present)
Main item (End collection)
Header
.... ..00 = bSize: 0 bytes (0)
.... 00.. = bType: Main (0)
1100 .... = bTag: End collection (0xc)
Main item (End collection)
Header
.... ..00 = bSize: 0 bytes (0)
.... 00.. = bType: Main (0)
1100 .... = bTag: End collection (0xc)
1 ответ
Когда вы декодируете дескриптор HID, он покажет форматы пакетов. К сожалению, в этом случае страницы использования определяются поставщиком, поэтому невозможно точно сказать, как следует интерпретировать каждое использование.
Я расшифровал его, используя hidrdd (заявление об отказе: я написал это, но это бесплатный открытый исходный код, поэтому у меня нет конфликта интересов) как:
//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
/*
06 A0FF (GLOBAL) USAGE_PAGE 0xFFA0 Vendor-defined
09 01 (LOCAL) USAGE 0xFFA00001 <-- Warning: Undocumented usage (document it by inserting 0001 into file FFA0.conf)
A1 01 (MAIN) COLLECTION 0x01 Application (Usage=0xFFA00001: Page=Vendor-defined, Usage=, Type=) <-- Error: COLLECTION must be preceded by a known USAGE
09 02 (LOCAL) USAGE 0xFFA00002 <-- Warning: Undocumented usage (document it by inserting 0002 into file FFA0.conf)
A1 00 (MAIN) COLLECTION 0x00 Physical (Usage=0xFFA00002: Page=Vendor-defined, Usage=, Type=) <-- Error: COLLECTION must be preceded by a known USAGE
06 A1FF (GLOBAL) USAGE_PAGE 0xFFA1 Vendor-defined
09 03 (LOCAL) USAGE 0xFFA10003 <-- Warning: Undocumented usage (document it by inserting 0003 into file FFA1.conf)
09 04 (LOCAL) USAGE 0xFFA10004 <-- Warning: Undocumented usage (document it by inserting 0004 into file FFA1.conf)
15 80 (GLOBAL) LOGICAL_MINIMUM 0x80 (-128)
25 7F (GLOBAL) LOGICAL_MAXIMUM 0x7F (127)
35 00 (GLOBAL) PHYSICAL_MINIMUM 0x00 (0) <-- Info: Consider replacing 35 00 with 34
45 FF (GLOBAL) PHYSICAL_MAXIMUM 0xFF (-1)
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
95 08 (GLOBAL) REPORT_COUNT 0x08 (8) Number of fields
81 02 (MAIN) INPUT 0x00000002 (8 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap <-- Error: PHYSICAL_MAXIMUM (-1) is less than PHYSICAL_MINIMUM (0)
09 05 (LOCAL) USAGE 0xFFA10005 <-- Warning: Undocumented usage (document it by inserting 0005 into file FFA1.conf)
09 06 (LOCAL) USAGE 0xFFA10006 <-- Warning: Undocumented usage (document it by inserting 0006 into file FFA1.conf)
15 80 (GLOBAL) LOGICAL_MINIMUM 0x80 (-128) <-- Redundant: LOGICAL_MINIMUM is already -128
25 7F (GLOBAL) LOGICAL_MAXIMUM 0x7F (127) <-- Redundant: LOGICAL_MAXIMUM is already 127
35 00 (GLOBAL) PHYSICAL_MINIMUM 0x00 (0) <-- Redundant: PHYSICAL_MINIMUM is already 0 <-- Info: Consider replacing 35 00 with 34
45 FF (GLOBAL) PHYSICAL_MAXIMUM 0xFF (-1) <-- Redundant: PHYSICAL_MAXIMUM is already -1
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field <-- Redundant: REPORT_SIZE is already 8
95 08 (GLOBAL) REPORT_COUNT 0x08 (8) Number of fields <-- Redundant: REPORT_COUNT is already 8
91 02 (MAIN) OUTPUT 0x00000002 (8 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap <-- Error: PHYSICAL_MAXIMUM (-1) is less than PHYSICAL_MINIMUM (0)
C0 (MAIN) END_COLLECTION Physical <-- Warning: Physical units are still in effect PHYSICAL(MIN=0,MAX=-1) UNIT(0x,EXP=0)
C0 (MAIN) END_COLLECTION Application <-- Warning: Physical units are still in effect PHYSICAL(MIN=0,MAX=-1) UNIT(0x,EXP=0)
*/
//--------------------------------------------------------------------------------
// Vendor-defined inputReport (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
// No REPORT ID byte
// Collection: CA: CP:
int8_t VEN_0003; // Usage 0xFFA10003: , Value = -128 to 127, Physical = (Value + 128) x -1 / 255
int8_t VEN_0004[7]; // Usage 0xFFA10004: , Value = -128 to 127, Physical = (Value + 128) x -1 / 255
} inputReport_t;
//--------------------------------------------------------------------------------
// Vendor-defined outputReport (Device <-- Host)
//--------------------------------------------------------------------------------
typedef struct
{
// No REPORT ID byte
// Collection: CA: CP:
int8_t VEN_0005; // Usage 0xFFA10005: , Value = -128 to 127, Physical = (Value + 128) x -1 / 255
int8_t VEN_0006[7]; // Usage 0xFFA10006: , Value = -128 to 127, Physical = (Value + 128) x -1 / 255
} outputReport_t;
Как вы можете видеть, описанный выше дескриптор HID имеет некоторые проблемы (например, физический максимум 45 FF равен -1, но я думаю, что они имели в виду 255 - что должно быть представлено как 46 FF 00), но проблема остается в том, что он ничего не говорит о смысл использования. Кстати, даже Wireshark не сообщил правильно логический минимум: 15 80 - это -128, а не 128.
Все, что мы можем из этого сказать, это то, что отчеты имеют длину 8 байтов и что первый байт, по-видимому, является своего рода идентификатором (ну, его использование отличается от остальных 7 байтов).
Только драйвер поставщика знает, как интерпретировать отчеты, но с достаточным количеством перехватов пакетов Wireshark, полученных в контролируемых условиях, вы можете быть в состоянии произвести реинжиниринг работоспособной интерпретации.
Извините, но это лучшее, что я могу с этим сделать.
Я тоже купил децибелиметр, он совместим с вашей моделью. В настоящее время я пытаюсь перенести этот код на сценарий bash: https://github.com/dobra-noc/gm1356, который отлично работает для меня с моим устройством (что, кстати, даже не gm1356), и я предполагаю, что это будет работать и для вас.