HID Temperature Device Report Reading

1.7k views Asked by At

I have been given a project which includes the integration of a Temperature & Humidity USB sensor into my company’s application. I must confess that I have complete awareness about the communication with a HID device.

So, there is a USB sensor from a Chinese manufacturer that came with no documentation but only with a MS Windows application that reads current temperature & humidity and also reads all records which are stored in internal memory by using a library called SLABHidDevice.dll. I contacted the vendor of the device but also the Silicon Labs Company (creators of SLABHidDevice.dll) for some documentation or help, both with no luck.

After trying with many USB sniffer applications like USBlyzer, USBTrace, etc. I found out what kind of bytes the HID device needs to send a Report back, so I created a C# demo application using many HID libraries. By sniffing the USB device, I managed to simulate the correct request that triggers the device to output the correct reply.

My problem is the following: I manage to connect with the device using VID & PID (VendorID, ProductID), I am also able to get some details of the device like SerialNumber, DevicePath, MaxInputReportLength, etc. Moreover, I can ask for a Report using GetInputReport() function, providing a buffer which contains the wanted Report ID into the first byte (e.g. 0x05) and also I can read the buffer that is returned from the above function. Unfortunately, the buffer does not contain any readable information by me (e.g. /n.Ô.Ï.P..ô.d.¶). While reading many documents about HIDs Reports, I realized that there are Report Descriptors into any HID device firmware that contain the structure of all the reports that can be imported/exported.

So, my main question is: Do I need to have any kind of device-specific documentation to translate the buffer into readable data or can I extract my data from the buffer, using the Report Descriptor that the device outputs?

Below I include the Report Descriptor for my device that is extracted using USBlyzer app:

Interface 0 HID Report Descriptor Vendor-Defined 1
Item Tag (Value) Raw Data 
Usage Page (Vendor-Defined 1) 06 00 FF  
Usage (Vendor-Defined 1) 09 01  
Collection (Application) A1 01  
    Report ID (1) 85 01  
    Report Count (4) 95 04  
    Report Size (8) 75 08  
    Logical Maximum (255) 26 FF 00  
    Logical Minimum (0) 15 00  
    Usage (Vendor-Defined 1) 09 01
    Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) 91 02

    Report ID (2) 85 02  
    Report Count (60) 95 3C  
    Report Size (8) 75 08  
    Logical Maximum (255) 26 FF 00  
    Logical Minimum (0) 15 00  
    Usage (Vendor-Defined 1) 09 01  
    Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) 91 02

    Report ID (3) 85 03  
    Report Count (1) 95 01  
    Report Size (8) 75 08  
    Logical Maximum (255) 26 FF 00  
    Logical Minimum (0) 15 00  
    Usage (Vendor-Defined 1) 09 01  
    Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) 91 02

    Report ID (4) 85 04  
    Report Count (2) 95 02  
    Report Size (8) 75 08  
    Logical Maximum (255) 26 FF 00  
    Logical Minimum (0) 15 00  
    Usage (Vendor-Defined 1) 09 01  
    Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) 91 02  

    Report ID (5) 85 05  
    Report Count (31) 95 1F  
    Report Size (8) 75 08  
    Logical Maximum (255) 26 FF 00  
    Logical Minimum (0) 15 00  
    Usage (Vendor-Defined 1) 09 01  
    Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02  

    Report ID (6) 85 06  
    Report Count (60) 95 3C  
    Report Size (8) 75 08  
    Logical Maximum (255) 26 FF 00  
    Logical Minimum (0) 15 00  
    Usage (Vendor-Defined 1) 09 01  
    Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02  

    Report ID (7) 85 07  
    Report Count (60) 95 3C  
    Report Size (8) 75 08  
    Logical Maximum (255) 26 FF 00  
    Logical Minimum (0) 15 00  
    Usage (Vendor-Defined 1) 09 01  
    Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02 

    Report ID (8) 85 08  
    Report Count (60) 95 3C  
    Report Size (8) 75 08  
    Logical Maximum (255) 26 FF 00  
    Logical Minimum (0) 15 00  
    Usage (Vendor-Defined 1) 09 01  
    Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02 

    Report ID (9) 85 09  
    Report Count (9) 95 09  
    Report Size (8) 75 08  
    Logical Maximum (255) 26 FF 00  
    Logical Minimum (0) 15 00  
    Usage (Vendor-Defined 1) 09 01  
    Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) 91 02  
End Collection C0

If device-specific documentation is needed then there is nothing I could do. However, if no documentation is needed, I would like any help or suggestion from anyone who has some experience with HID communication.

EDIT: After removing the lid of the device, I figured out that the main microcontroller which -I think- does all the work, is the Silab F321.

I also attach a photo of the device for further information. (Can't post it directly due to my little reputation score)

Thank you.

2

There are 2 answers

4
aja On

Do I need to have any kind of device-specific documentation to translate the buffer into readable data can I extract my data from the buffer, using the Report Descriptor that the device outputs?

Yes and No. Yes, you can use the Report Descriptor to mechanically parse the responses and build requests that the device will process. But in this case, No, because the fields (usages) that comprise each request/response (report) are vendor-defined so you will need vendor-supplied documentation that describes the meaning of each report. Knowing that the chip is a Silab F321 doesn't really help you either because it is just a variant of an 8051 microcontroller that has a built in USB function - the data logger vendor (not the 8051 chip vendor) has coded the meaning of each report in their firmware.

From the above Report Descriptor, it appears that the vendor has taken some short cuts too. Normally you would define a unique "usage" code for say, Temperature, Pressure, Humidity and define reports that contain one or more of those. In this case, they seem to be using the Report ID to determine the meaning of each "usage" - that is, the usage code is fixed at 1 (and so doesn't convey any meaning) and the Report Id is being used to identify the content of each report. However, that doesn't help you because you still don't know what the vendor intended each report to mean.

You could attempt to "reverse engineer" the meanings but I wouldn't recommend basing an application on a reverse engineered interface.

The following is a mechanically generated bunch of C structure definitions from the above report descriptor (by a tool called hidrdd), but it still can't help you with the meanings of each report:

//--------------------------------------------------------------------------------
// Vendor-defined inputReport 05 (Device --> Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x05 (5)
  uint8_t  VEN_VendorDefined0001[31];                // Usage 0xFF000001: , Value = 0 to 255
} inputReport05_t;


//--------------------------------------------------------------------------------
// Vendor-defined inputReport 06 (Device --> Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x06 (6)
  uint8_t  VEN_VendorDefined0001[60];                // Usage 0xFF000001: , Value = 0 to 255
} inputReport06_t;


//--------------------------------------------------------------------------------
// Vendor-defined inputReport 07 (Device --> Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x07 (7)
  uint8_t  VEN_VendorDefined0001[60];                // Usage 0xFF000001: , Value = 0 to 255
} inputReport07_t;


//--------------------------------------------------------------------------------
// Vendor-defined inputReport 08 (Device --> Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x08 (8)
  uint8_t  VEN_VendorDefined0001[60];                // Usage 0xFF000001: , Value = 0 to 255
} inputReport08_t;


//--------------------------------------------------------------------------------
// Vendor-defined outputReport 01 (Device <-- Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x01 (1)
  uint8_t  VEN_VendorDefined0001[4];                 // Usage 0xFF000001: , Value = 0 to 255
} outputReport01_t;


//--------------------------------------------------------------------------------
// Vendor-defined outputReport 02 (Device <-- Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x02 (2)
  uint8_t  VEN_VendorDefined0001[60];                // Usage 0xFF000001: , Value = 0 to 255
} outputReport02_t;


//--------------------------------------------------------------------------------
// Vendor-defined outputReport 03 (Device <-- Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x03 (3)
  uint8_t  VEN_VendorDefined0001;                    // Usage 0xFF000001: , Value = 0 to 255
} outputReport03_t;


//--------------------------------------------------------------------------------
// Vendor-defined outputReport 04 (Device <-- Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x04 (4)
  uint8_t  VEN_VendorDefined0001[2];                 // Usage 0xFF000001: , Value = 0 to 255
} outputReport04_t;


//--------------------------------------------------------------------------------
// Vendor-defined outputReport 09 (Device <-- Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x09 (9)
  uint8_t  VEN_VendorDefined0001[9];                 // Usage 0xFF000001: , Value = 0 to 255
} outputReport09_t;
0
user9156702 On

If this is still valid guestion. You have to check which values are changing the byte[] buffer?

5 0 0 79 200 1 94 2 205 1 111 1 144 1 244 0 100 3 182 0 3 1 1 0 0 0 0 0 0 0 0 9

for example from that data bytes 6 & 7 could hold the value that you are after

-> 1 94 -> hex 1 5e -> dec 350 -> /10 -> 35.0

Also some data might be added with magic number for example bytes 8 & 9 :

2 205 -> hex 2 cd -> dec 717 - 400 (magic) -> 317 /10 -> 31.7