0

I have a Digital Sound Level Meter (sonometer) GM1356 with USB. There is some software to handle it on Windows, however I don't have CD and it's not available on the internet. What I want do to is to read it's data about current noise level on Linux.

I found already a library that allows me to do this in a language I know (ruby, libusb). In next step I installed wireshark to check out what it sends do the pc. It doesn't send too much. The most interesting packet I found is DESCRIPTOR HID Report. I wonder what next steps should I take to read data that is interesting for me. How can I determine what requests I should send to get it?

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)
ciemborowicz
  • 93
  • 1
  • 10
  • 1
    What is the HID descriptor in hex? (in Wireshark right click and choose Copy then ...as Hex Dump). – aja May 27 '19 at 04:36
  • @aja 0000 00 a9 d7 d6 00 88 ff ff 43 02 80 06 01 00 2d 00 0010 b2 26 ec 5c 00 00 00 00 ea e9 05 00 00 00 00 00 0020 34 00 00 00 34 00 00 00 00 00 00 00 00 00 00 00 0030 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 0040 06 a0 ff 09 01 a1 01 09 02 a1 00 06 a1 ff 09 03 0050 09 04 15 80 25 7f 35 00 45 ff 75 08 95 08 81 02 0060 09 05 09 06 15 80 25 7f 35 00 45 ff 75 08 95 08 0070 91 02 c0 c0 – ciemborowicz May 27 '19 at 18:07
  • @aja Oh, sorry, this was Hex of `DESCRIPTOR HID Report`. Here is `HID DESCRIPTOR` from `DESCRIPTOR Response CONFIGURATION`: 0000 09 21 10 01 00 01 22 34 00 – ciemborowicz May 27 '19 at 18:38

2 Answers2

1

When you decode the HID descriptor it will show the packet formats. Unfortunately, in this case the usage pages are vendor-defined so it is not possible to say exactly how each usage is to be interpreted.

I decoded it using hidrdd (disclaimer: I wrote it, but it is free open source so I have no conflict of interest) as:

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

As you can see, the above HID descriptor has some issues (for example, physical maximum 45 FF is -1, but I think they meant 255 - which should be represented as 46 FF 00) but the problem remains that it tells you nothing about the meaning of the usages. BTW, even Wireshark has not reported the logical minimum correctly: 15 80 is -128 not 128.

All we can tell from it is that the reports are 8-bytes long and that the first byte seems to be some kind of id (well, its usage is different from the remaining 7 bytes).

Only the vendor's driver knows how to interpret the reports, but with a sufficient number of Wireshark packet captures obtained under controlled conditions you may be able reverse engineer a workable interpretation.

Sorry, but that's the best I can do with this.

aja
  • 1,525
  • 17
  • 20
  • Thank you very much for answer. Yesterday I received software for Windows which works with my device and I tried to sniff the protocol. Here is what I came to: https://github.com/ciembor/gm1356-for-linux/blob/master/PROTOCOL.md. I try to mimic it on Linux with libusb for Ruby but i struggle with this: https://stackoverflow.com/questions/56360704/i-cannot-mimic-sniffed-urb-interruption-using-libusb-for-ruby. – ciemborowicz May 29 '19 at 12:53
  • I mark it as solved, because it is probably not possible to get more information from these descriptors. – ciemborowicz May 29 '19 at 20:57
  • One more question, do you have any idea why someone could define sonometer as a HID device? In my opinion it doesn't make any sense. – ciemborowicz May 29 '19 at 20:59
0

I bought a decibelimeter too, which happens to be compatible with your model. I am currently trying to port this code to a bash script: https://github.com/dobra-noc/gm1356 which works fine for me with my device (which btw isn't even the gm1356) and I'm guessing it will work for you too.