IntergatedCircuits / HidSharp

HIDSharp is a multiplatform C# library for USB HID devices by James F. Bellinger
https://www.zer7.com/software/hidsharp
Other
121 stars 34 forks source link

Relative axis with signed value #14

Open sonik-br opened 2 years ago

sonik-br commented 2 years ago

Hi. I'm interfacing with a game controller and it have a "Dial" axis. It's a relative axis and it's value is signed. It works like an mouse wheel (scrolling can be negative or positive). But the lib returns it as unsiged. Lib register it with range of 0 to 127 but the correct is -128 to 127

\\?\hid#vid_2341&pid_8036&mi_02#8&7616083&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
Arduino LLC Arduino Leonardo MiSTer-A1 JogCon (VID 9025, PID 32822, version 1.0)
Max Lengths: Input 6, Output 0, Feature 0
Serial Ports: \\.\COM11
Report Descriptor:
  05 01 09 04 A1 01 05 09 19 01 29 10 15 00 25 01 35 00 45 01 65 00 55 00 75 01 95 10 81 03 05 01 09 39 25 07 46 3B 01 65 14 75 08 95 01 81 02 09 37 25 7F 81 06 09 38 15 00 25 FF 81 02 C1 00 (63 bytes)
  UsagePage 1
  Usage 4
  Collection 1
    UsagePage 9
    UsageMinimum 1
    UsageMaximum 16
    LogicalMinimum 0
    LogicalMaximum 1
    PhysicalMinimum 0
    PhysicalMaximum 1
    Unit 0
    UnitExponent 0
    ReportSize 1
    ReportCount 16
    Input 3
    UsagePage 1
    Usage 57
    LogicalMaximum 7
    PhysicalMaximum 315
    Unit 20
    ReportSize 8
    ReportCount 1
    Input 2
    Usage 55
    LogicalMaximum 127
    Input 6
    Usage 56
    LogicalMinimum 0
    LogicalMaximum 255
    Input 2
  EndCollection 0
Usage: 10004 GenericDesktopJoystick
Input: ReportID=0, Length=6, Items=4
  16 Elements x 1 Bits, Units: None, Expected Usage Type: 0, Flags: Constant, Variable, Usages: 90001 Button1, 90002 Button2, 90003 Button3, 90004 Button4, 90005 Button5, 90006 Button6, 90007 Button7, 90008 Button8, 90009 Button9, 9000A Button10, 9000B Button11, 9000C Button12, 9000D Button13, 9000E Button14, 9000F Button15, 90010 Button16
  1 Elements x 8 Bits, Units: EnglishRotation, Expected Usage Type: 0, Flags: Variable, Usages: 10039 GenericDesktopHatSwitch
  1 Elements x 8 Bits, Units: EnglishRotation, Expected Usage Type: 0, Flags: Variable, Relative, Usages: 10037 GenericDesktopDial
  1 Elements x 8 Bits, Units: EnglishRotation, Expected Usage Type: 0, Flags: Variable, Usages: 10038 GenericDesktopWheel

Windows joy.cpl shows it correctly. By using an HID descriptor viewer (USBlyzer) it shows the range -128 to 127 image

I'm doing something wrong?

benedekkupper commented 2 years ago

Hi! Can you frame your question/inquiry/report in the terms of this actual library? I have no idea how this "HID Demo" program is associated with HidSharp.

sonik-br commented 2 years ago

Oh sorry. My bad. I was testing two libs and got confused. I have edited my first.

benedekkupper commented 2 years ago

So maybe you got here from win-hid-dump or similar, looking to see the same HID report descriptor from your C# application, as your device reports it. Unfortunately that's not how Windows works. The Windows OS doesn't expose the HID report descriptor to its userspace, instead it gives a higher level preprocessed property set. HidSharp attempts to reverse engineer the approximate report descriptor from this information (see WinHidDevice.ReportDescriptorReconstructor.cs), but this will never be accurate. What we would need to find out if the OS is mistaking -128 for 0, or HidSharp.

Before we venture into that, I have to ask, do you have the means to change the report descriptor on your USB device? It's not really justifiable to have an asymmetrical range such as [-128, 127], and most devices use [-127, 127] instead.

sonik-br commented 2 years ago

It's possible to change as it is an arduino based, open source project. But it's used to interface with playstation controllers and I think it is this way to make it easier to map the 256 bit range to it as it will just use the raw bits. Makes sense? signed byte vs unsigned byte.

For the descriptor I used USBlyzer to capture. It installs as a (kernel?) driver and it can capture any kind of usb traffic on windows.

The device descriptor from source code matches the report from USBlyzer.

0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
0x09, 0x04,        // Usage (Joystick)
0xA1, 0x01,        // Collection (Application)
0xA1, 0x00,        //   Collection (Physical)
0x05, 0x09,        //     Usage Page (Button)
0x19, 0x01,        //     Usage Minimum (0x01)
0x29, 0x0C,        //     Usage Maximum (0x0C)
0x15, 0x00,        //     Logical Minimum (0)
0x25, 0x01,        //     Logical Maximum (1)
0x95, 0x10,        //     Report Count (16)
0x75, 0x01,        //     Report Size (1)
0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
0x09, 0x01,        //     Usage (Pointer)
0xA1, 0x00,        //     Collection (Physical)
0x09, 0x30,        //       Usage (X)
0x09, 0x31,        //       Usage (Y)
0x15, 0x80,        //       Logical Minimum (-128)
0x25, 0x7F,        //       Logical Maximum (127)
0x95, 0x02,        //       Report Count (2)
0x75, 0x08,        //       Report Size (8)
0x81, 0x02,        //       Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              //     End Collection
0x09, 0x37,        //     Usage (Dial)
0x15, 0x80,        //     Logical Minimum (-128)
0x25, 0x7F,        //     Logical Maximum (127)
0x95, 0x01,        //     Report Count (1)
0x75, 0x08,        //     Report Size (8)
0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x38,        //     Usage (Wheel)
0x15, 0x00,        //     Logical Minimum (0)
0x26, 0xFF, 0x00,  //     Logical Maximum (255)
0x95, 0x01,        //     Report Count (1)
0x75, 0x08,        //     Report Size (8)
0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x39,        //     Usage (Hat switch)
0x15, 0x00,        //     Logical Minimum (0)
0x25, 0x07,        //     Logical Maximum (7)
0x35, 0x00,        //     Physical Minimum (0)
0x46, 0x3B, 0x01,  //     Physical Maximum (315)
0x75, 0x08,        //     Report Size (8)
0x95, 0x01,        //     Report Count (1)
0x65, 0x14,        //     Unit (System: English Rotation, Length: Centimeter)
0x81, 0x42,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0xC0,              //   End Collection
0xC0,              // End Collection

The GetRawReportDescriptor method returns the preprocessed windows descriptor? By parsing it I can see how it messes up from the original.

0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
0x09, 0x04,        // Usage (Joystick)
0xA1, 0x01,        // Collection (Application)
0x05, 0x09,        //   Usage Page (Button)
0x19, 0x01,        //   Usage Minimum (0x01)
0x29, 0x10,        //   Usage Maximum (0x10)
0x15, 0x00,        //   Logical Minimum (0)
0x25, 0x01,        //   Logical Maximum (1)
0x35, 0x00,        //   Physical Minimum (0)
0x45, 0x01,        //   Physical Maximum (1)
0x65, 0x00,        //   Unit (None)
0x55, 0x00,        //   Unit Exponent (0)
0x75, 0x01,        //   Report Size (1)
0x95, 0x10,        //   Report Count (16)
0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01,        //   Usage Page (Generic Desktop Ctrls)
0x09, 0x39,        //   Usage (Hat switch)
0x25, 0x07,        //   Logical Maximum (7)
0x46, 0x3B, 0x01,  //   Physical Maximum (315)
0x65, 0x14,        //   Unit (System: English Rotation, Length: Centimeter)
0x75, 0x08,        //   Report Size (8)
0x95, 0x01,        //   Report Count (1)
0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x37,        //   Usage (Dial)
0x25, 0x7F,        //   Logical Maximum (127)
0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x38,        //   Usage (Wheel)
0x15, 0x00,        //   Logical Minimum (0)
0x25, 0xFF,        //   Logical Maximum (-1)
0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC1, 0x00,        // End Collection
sonik-br commented 2 years ago

At least after calling the win32 method it's returning a signed value

image