Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nut usbhid driver unable to find HID descriptors on interfaces other than interface 0 #1840

Closed
x0ul opened this issue Jan 25, 2023 · 18 comments
Labels
enhancement impacts-release-2.7.3-or-older Issues reported against NUT release 2.7.3 or older, packaged or custom builds of code from that era impacts-release-2.7.4 Issues reported against NUT release 2.7.4 (maybe vanilla or with minor packaging tweaks) impacts-release-2.8.0 Issues reported against NUT release 2.8.0 (maybe vanilla or with minor packaging tweaks) USB non-zero interface numbers Most UPSes serve USB interactions on interface 0 which is default. Recent "composite devices" differ USB
Milestone

Comments

@x0ul
Copy link

x0ul commented Jan 25, 2023

Hi there, I have a UPS that seems to speak HID, but its configuration has two different interfaces under its (single) configuration. Interface 0 is small and has some vendor-specific junk, while interface 1 dumps a bunch of HID data and most of it fits into usages 0x84 and 0x85, resembling what is expected from a UPS. However, the usbhid driver in nut seems to be unable to communicate with interface 1, so it only sees the small junky data from interface 0 and doesn't think there's a UPS there.

Some data from usbhid-dump showing the two interfaces on my UPS.

Interface 0. Small, bad.

002:004:000:DESCRIPTOR
 06 00 FF 09 01 A1 01 09 02 15 00 26 FF 00 75 08
 95 08 81 82 09 02 95 08 91 82 C0

Interface 1. Big, good.

002:004:001:DESCRIPTOR
 05 84 09 04 A1 01 09 24 A1 00 85 28 09 FE 79 01
 75 08 95 01 15 00 26 FF 00 B1 03 85 29 09 FF 79
 05 B1 03 85 2B 09 FD 79 03 B1 03 09 1A A1 02 85
 30 09 40 67 21 D1 F0 00 55 07 B1 83 C0 85 11 09
 5A 75 08 95 01 15 01 25 03 65 00 55 00 B1 82 09
 02 A1 02 85 32 75 01 95 07 15 00 25 01 81 03 B1
 03 09 62 95 01 B1 A2 09 62 81 A2 B1 01 81 01 09
... (truncated by me)

I pasted both those into hidrd-convert and see the nice-looking 0x84, 0x85 usage pages (more here if you care to see).

Some specifics now that I've introduced the problem and my interpretation. The UPS is a Liebert PST5 made by Virtiv and was bought on Amazon in the last month. The device's vid is 10af; pid is 0002. This sort of matches the Belkin HID driver, so I started from there trying to get it to work after adding a specific pid to match in ups.conf.

I hacked nut into talking to interface 1 and getting some decent data (perhaps incomplete, I stopped once I got comms working) with the following:

diff --git a/drivers/belkin-hid.c b/drivers/belkin-hid.c
index 686dc9261..46cfddf0c 100644
--- a/drivers/belkin-hid.c
+++ b/drivers/belkin-hid.c
@@ -31,6 +31,8 @@
 
 #include <math.h>     /* for fabs() */
 
+static usb_communication_subdriver_t *usb = &usb_subdriver;
+
 #define BELKIN_HID_VERSION      "Belkin/Liebert HID 0.18"
 
 /* Belkin */
@@ -71,6 +73,8 @@ static usb_device_id_t belkin_usb_device_table[] = {
        { USB_DEVICE(LIEBERT_VENDORID, 0x0004), NULL },
        /* Liebert PowerSure PSA UPS */
        { USB_DEVICE(LIEBERT_VENDORID, 0x0001), NULL },
+       /* Liebert PowerSure PST UPS */
+       { USB_DEVICE(LIEBERT_VENDORID, 0x0002), NULL },
        /* Liebert PowerSure PSI 1440 */
        { USB_DEVICE(LIEBERT_VENDORID, 0x0004), NULL },
        /* Liebert GXT3 */
@@ -424,7 +428,7 @@ static usage_lkp_t belkin_usage_lkp[] = {
 };
 
 static usage_tables_t belkin_utab[] = {
-       belkin_usage_lkp,
+       // belkin_usage_lkp,
        hid_usage_lkp,
        NULL,
 };
@@ -625,6 +629,8 @@ static int belkin_claim(HIDDevice_t *hd)
                return 0;
 
        case SUPPORTED:
+               usb->hid_rep_index = 1;
+               usb->hid_desc_index = 1;
                return 1;
 
        case NOT_SUPPORTED:

This hack I specifically made because according to the docs for libusb_get_config_descriptor, the argument usb_subdriver.hid_rep_index represents the USB configuration, not the interface. In other code, namely the call to usb_claim_interface hid_rep_index is passed in as interface. This device only has one configuration, so I hard-coded the parameter to 0 here in order to make it work quickly for me. To me it seems like hid_rep_index should not be used for both configuration and interface, but I have not read enough nut code to really understand how it's used in depth.

diff --git a/drivers/libusb1.c b/drivers/libusb1.c
index 048aa7c51..79e1cc3b9 100644
--- a/drivers/libusb1.c
+++ b/drivers/libusb1.c
@@ -381,7 +381,8 @@ static int nut_libusb_open(libusb_device_handle **udevp,
 
                upsdebugx(2, "Reading first configuration descriptor");
                ret = libusb_get_config_descriptor(device,
-                       (uint8_t)usb_subdriver.hid_rep_index,
+                               0,
+                       // (uint8_t)usb_subdriver.hid_rep_index,
                        &conf_desc);
                /*ret = libusb_get_active_config_descriptor(device, &conf_desc);*/
                if (ret < 0)

Evidence of communication after the hack above to talk to interface 1:

$ sudo /usr/local/ups/bin/upsc ups@localhost 
battery.charge: 1
battery.charge.warning: 30
battery.runtime: 1192
battery.type: PbAc
battery.voltage: 0.1
battery.voltage.nominal: 1
device.mfr: Vertiv Co 
device.model: Liebert PST5  
device.serial: 
device.type: ups
driver.name: usbhid-ups
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.synchronous: auto
driver.parameter.vendorid: 10af
driver.state: quiet
driver.version: 2.8.0-Windows-491-gb27a0e76a
driver.version.data: Belkin/Liebert HID 0.18
driver.version.internal: 0.49
driver.version.usb: libusb-1.0.23 (API: 0x1000107)
input.frequency: 0.1
input.frequency.nominal: 1
input.sensitivity: reduced
input.transfer.high: 1
input.transfer.high.max: 1
input.transfer.high.min: 1
input.transfer.low: 1
input.transfer.low.max: 1
input.transfer.low.min: 1
input.voltage: 0.1
input.voltage.nominal: 1
output.frequency: 0.1
output.voltage: 0.1
ups.beeper.status: disabled
ups.delay.shutdown: 20
ups.delay.start: 30
ups.firmware: 0
ups.load: 1
ups.load.high: 1
ups.mfr: Vertiv Co 
ups.model: Liebert PST5  
ups.power.nominal: 1
ups.productid: 0002
ups.serial: 
ups.status: OB CHRG
ups.test.result: Done and passed
ups.timer.reboot: 1
ups.timer.shutdown: 1
ups.timer.start: 1
ups.type: offline
ups.vendorid: 10af

It'd be really cool to get this UPS supported, I bet there are other ones out there with the same little idiosyncrasy. I'm not sure how to make my hacky patch into a serious fix, but here it is in case you find it useful. Thanks for the nice software :)

@jimklimov jimklimov added the USB label Jan 26, 2023
@jimklimov
Copy link
Member

For context, I think whatever support for non-zero interface numbers we have currently, is from #1044 (and possibly later commits in areas it touched upon - check by "git blame" or equivalent github UI). Which means it is relatively recent, was confirmed to "scratch one itch" and might be or not be incomplete for the general case.

May I suggest you look at that PR (and possible differences of that codebase from current master), and try to craft, test and post a PR for a better solution? Something with a driver configuration option, debug messages to see there's more than one interface, probing for which one is HID, etc? :)

Also note #1819 (and a few recent PRs before it) that touched on "common USB matching" codebase: if the solution is to be generic, it should probably land into these methods of libusb0, libusb1 and scan_usb files.

@exuvo
Copy link

exuvo commented Jun 15, 2023

I just bought a Vertive Edge 750VA, which seems to behave similarly to this with 1 configuration that has 2st interfaces, the first one tiny (27 bytes) and the second one large (662 bytes).

idVendor           0x10af Liebert Corp.
idProduct          0x0002 PowerSure PST UPS
bcdDevice            2.00
iManufacturer           1 Vertiv Co.
iProduct                2 Vertiv Edge

Before i start patching code, is the usb_set_altinterface setting supposed to do this or is that something unrelated?

@jimklimov
Copy link
Member

Looking at https://github.com/search?q=repo%3Anetworkupstools%2Fnut%20usb_set_altinterface&type=code - it might help. At least, should be easy to verify by a configuration file tweak...

@exuvo
Copy link

exuvo commented Jun 17, 2023

The setting did not work:
nut_usb_set_altinterface: libusb_set_interface_alt_setting(udev, 0, 1) returned -5 (Entity not found)

@jimklimov
Copy link
Member

jimklimov commented Jun 17, 2023

Thanks! In the meanwhile, I've got back to computers and re-checked the current source code (still matches the changes of PR #1044 in this area): it seems the hid_rep_index is the value we are after, and currently it is not tunable (just set in a couple of drivers for devices known to need a non-zero value). That would be the second argument in the call you posted above (which is 0 now).

Probably the easiest way forward would be to add a consistent (applicable to all libusb-based drivers) handling of config variables to tune hid_rep_index and perhaps hid_desc_index, hid_ep_in and hid_ep_out while at it. This would allow experimentation with new devices, like that done here, to see if the drivers need to be adapted in a fashion similar to existing one (hardcode it for devices where certain vendor/product/bcd/... ID or string values match a known pattern). Even if development stopped here at adding the config-option handling, it would already let users tweak their set-ups to actually let NUT handle the devices they have.

The point you've brought up above about sizes of replies on different interface numbers (and for that matter - now wondering if there is a way to query how many interfaces a device has and/or get an array of specific numbers present in case there may be "holes", to iterate them properly - for one or both generations of libusb backend) sounds like another decent approach for auto-detection of the usable interface. Maybe in nut-scanner with toggles added per previous paragraph, or in the drivers where they might maybe misfire but when they work - would be more convenient.

You offered to hack about this - would you care to post a PR to score those points? I'm a bit short on time, and lack a device with non-zero interface to test a fix, and in terms of community-building it is better to get more people well versed with the codebase :D

@jimklimov jimklimov added the USB non-zero interface numbers Most UPSes serve USB interactions on interface 0 which is default. Recent "composite devices" differ label Jun 17, 2023
@exuvo
Copy link

exuvo commented Jun 18, 2023

Yes i can probably add those settings. My vacation starts after next week and i have nothing else planned.
It is certainly possible to scan the interface sizes as that is what lsusb did for me:
Notice the wDescriptorLength difference.

# lsusb -d 10af:0002 -v

Bus 003 Device 002: ID 10af:0002 Liebert Corp. PowerSure PST UPS
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x10af Liebert Corp.
  idProduct          0x0002 PowerSure PST UPS
  bcdDevice            2.00
  iManufacturer           1 Vertiv Co.
  iProduct                2 Vertiv Edge
  iSerial                 3 2018010003ED13C
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x003b
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xe0
      Self Powered
      Remote Wakeup
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 
      bInterfaceProtocol      0 
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.11
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      27
          Report Descriptor: (length is 27)
            Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
                            (null)
            Item(Local ): Usage, data= [ 0x01 ] 1
                            (null)
            Item(Main  ): Collection, data= [ 0x01 ] 1
                            Application
            Item(Local ): Usage, data= [ 0x02 ] 2
                            (null)
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Report Count, data= [ 0x08 ] 8
            Item(Main  ): Input, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Local ): Usage, data= [ 0x02 ] 2
                            (null)
            Item(Global): Report Count, data= [ 0x08 ] 8
            Item(Main  ): Output, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Main  ): End Collection, data=none
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               8
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 
      bInterfaceProtocol      0 
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.11
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength     662
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               8
Device Status:     0x0001
  Self Powered

@jimklimov
Copy link
Member

Thanks, that would be very welcome (and hopefully fun for you too) :)

@jimklimov jimklimov added impacts-release-2.8.0 Issues reported against NUT release 2.8.0 (maybe vanilla or with minor packaging tweaks) impacts-release-2.7.4 Issues reported against NUT release 2.7.4 (maybe vanilla or with minor packaging tweaks) impacts-release-2.7.3-or-older Issues reported against NUT release 2.7.3 or older, packaged or custom builds of code from that era labels Jun 27, 2023
@3lorsin
Copy link

3lorsin commented Jan 1, 2024

Hello There,
Has there been any progress on this?
I just ended up with a Vertiv Liebert PST5 and after following the advice found at https://www.mail-archive.com/[email protected]/msg01090.html I was able to get the linux host and UPS talking, however, the data is very limited. See below:

$ sudo upsc 3DUPS
Init SSL without certificate database
device.mfr: Vertiv Co.
device.model: Liebert PST5
device.serial: 2322410918A4A3C
device.type: ups
driver.name: usbhid-ups
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.productid: 0002
driver.parameter.synchronous: no
driver.version: 2.7.4
driver.version.data: Belkin/Liebert HID 0.17
driver.version.internal: 0.41
ups.mfr: Vertiv Co.
ups.model: Liebert PST5
ups.productid: 0002
ups.serial: 2322410918A4A3C
ups.status: OB
ups.vendorid: 10af

What is also interesting, is NUT is reporting that the UPS is "On Battery" even though it isn't.

To me, this feels related to this issue, but I am not certain. Any advice is greatly appreciated.
Thank You!

@exuvo
Copy link

exuvo commented Jan 1, 2024

No i never implemented anything.

@jimklimov
Copy link
Member

There was some discussion and maybe work in recent months. Anyhow, it would not be part of NUT v2.7.4 (released some 7 years ago).

@3lorsin
Copy link

3lorsin commented Jan 2, 2024

Fair point on the 7 year old build. I was able to get a temporary raspberry pi server hooked up running 2.8.1 on arch linux arm and had the same result as above.
I did discover #2148 and #2188 that appear related. To me it looks like the backend support is there, but either the belkin sub driver needs updated (similar to the OP) or some ups.conf integration added.
I don't know how to implement those changes, but I am happy to test out a dev build if one becomes available.

@jimklimov
Copy link
Member

Hello, can you please check if #2331 helps regarding making these HID numbers tunable?

Follow https://github.com/networkupstools/nut/wiki/Building-NUT-for-in%E2%80%90place-upgrades-or-non%E2%80%90disruptive-tests with this branch for the build:

git clone https://github.com/jimklimov/nut -b issue-2149

@jrjparks
Copy link
Contributor

jrjparks commented Mar 1, 2024

@jimklimov I was able to get battery status showing with your change.

./clients/upsc UPS-1@localhost
battery.charge: 100
battery.charge.warning: 20
battery.runtime: 1800
battery.type: PbAc
device.mfr: Vertiv Co.
device.model: Liebert PSI5
device.serial: 
device.type: ups
driver.debug: 0
driver.flag.allow_killpower: 0
driver.name: usbhid-ups
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.product: Liebert PSI5
driver.parameter.productid: 0002
driver.parameter.serial: 
driver.parameter.synchronous: auto
driver.parameter.usb_hid_desc_index: 1
driver.parameter.usb_hid_ep_in: 1
driver.parameter.usb_hid_ep_out: 1
driver.parameter.usb_hid_rep_index: 1
driver.parameter.vendor: Vertiv Co.
driver.parameter.vendorid: 10AF
driver.state: updateinfo
driver.version: 2.8.0-3661-gbe6534e5d
driver.version.data: Belkin/Liebert HID 0.19
driver.version.internal: 0.52
driver.version.usb: libusb-1.0.26 (API: 0x1000109)
ups.mfr: Vertiv Co.
ups.model: Liebert PSI5
ups.productid: 0002
ups.serial: 
ups.status: OL CHRG
ups.vendorid: 10af

I did have to include the above change to drivers/belkin-hid.c from @x0ul to make it work for me.

diff --git a/drivers/belkin-hid.c b/drivers/belkin-hid.c
index 686dc9261..46cfddf0c 100644
--- a/drivers/belkin-hid.c
+++ b/drivers/belkin-hid.c
@@ -31,6 +31,8 @@
 
 #include <math.h>     /* for fabs() */
 
+static usb_communication_subdriver_t *usb = &usb_subdriver;
+
 #define BELKIN_HID_VERSION      "Belkin/Liebert HID 0.18"
 
 /* Belkin */
@@ -71,6 +73,8 @@ static usb_device_id_t belkin_usb_device_table[] = {
        { USB_DEVICE(LIEBERT_VENDORID, 0x0004), NULL },
        /* Liebert PowerSure PSA UPS */
        { USB_DEVICE(LIEBERT_VENDORID, 0x0001), NULL },
+       /* Liebert PowerSure PST UPS */
+       { USB_DEVICE(LIEBERT_VENDORID, 0x0002), NULL },
        /* Liebert PowerSure PSI 1440 */
        { USB_DEVICE(LIEBERT_VENDORID, 0x0004), NULL },
        /* Liebert GXT3 */
@@ -424,7 +428,7 @@ static usage_lkp_t belkin_usage_lkp[] = {
 };
 
 static usage_tables_t belkin_utab[] = {
-       belkin_usage_lkp,
+       // belkin_usage_lkp,
        hid_usage_lkp,
        NULL,
 };
@@ -625,6 +629,8 @@ static int belkin_claim(HIDDevice_t *hd)
                return 0;
 
        case SUPPORTED:
+               usb->hid_rep_index = 1;
+               usb->hid_desc_index = 1;
                return 1;
 
        case NOT_SUPPORTED:

Screenshot 2024-02-29 at 21-12-32 Network UPS Tools upsstats 2 8 0 UPS Status

Screenshot 2024-02-29 at 21-15-18 upsstat data tree of UPS-1

@jrjparks
Copy link
Contributor

jrjparks commented Mar 1, 2024

Also not sure how useful this is, but lsusb dumped this once for some reason.

$ lsusb -d 10af:0002 -v
Bus 001 Device 002: ID 10af:0002 Liebert Corp. PowerSure PST UPS
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0         8
  idVendor           0x10af Liebert Corp.
  idProduct          0x0002 PowerSure PST UPS
  bcdDevice            0.02
  iManufacturer           3 Vertiv Co.
  iProduct                1 Liebert PSI5
  iSerial                 2 XXXXXXXXXXXXXXX
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x003b
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0xe0
      Self Powered
      Remote Wakeup
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0
      bInterfaceProtocol      0
      iInterface              0
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.10
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      27
         Report Descriptors:
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               8
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0
      bInterfaceProtocol      0
      iInterface              0
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.10
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength     662
          Report Descriptor: (length is 662)
            Item(Global): Usage Page, data= [ 0x84 ] 132
                            Power Device Page
            Item(Local ): Usage, data= [ 0x04 ] 4
                            UPS
            Item(Main  ): Collection, data= [ 0x01 ] 1
                            Application
            Item(Local ): Usage, data= [ 0x24 ] 36
                            Power Summary
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Report ID, data= [ 0x28 ] 40
            Item(Local ): Usage, data= [ 0xfe ] 254
                            iProduct
            Item(Local ): String Index, data= [ 0x01 ] 1
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x29 ] 41
            Item(Local ): Usage, data= [ 0xff ] 255
                            iSerialNumber
            Item(Local ): String Index, data= [ 0x02 ] 2
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x2b ] 43
            Item(Local ): Usage, data= [ 0xfd ] 253
                            iManufacturer
            Item(Local ): String Index, data= [ 0x03 ] 3
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x1a ] 26
                            Input
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Report ID, data= [ 0x30 ] 48
            Item(Local ): Usage, data= [ 0x40 ] 64
                            Config Voltage
            Item(Global): Unit, data= [ 0x21 0xd1 0xf0 0x00 ] 15782177
                            System: SI Linear, Unit: Centimeter^2*Gram*Seconds^-3*Ampere^-1
            Item(Global): Unit Exponent, data= [ 0x07 ] 7
                            Unit Exponent: 7
            Item(Main  ): Feature, data= [ 0x83 ] 131
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Report ID, data= [ 0x11 ] 17
            Item(Local ): Usage, data= [ 0x5a ] 90
                            Audible Alarm Control
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Logical Minimum, data= [ 0x01 ] 1
            Item(Global): Logical Maximum, data= [ 0x03 ] 3
            Item(Global): Unit, data= [ 0x00 ] 0
                            System: None, Unit: (None)
            Item(Global): Unit Exponent, data= [ 0x00 ] 0
                            Unit Exponent: 0
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Local ): Usage, data= [ 0x02 ] 2
                            Present Status
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Report ID, data= [ 0x32 ] 50
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x07 ] 7
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x62 ] 98
                            Internal Failure
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Main  ): Feature, data= [ 0xa2 ] 162
                            Data Variable Absolute No_Wrap Linear
                            No_Preferred_State No_Null_Position Volatile Bitfield
            Item(Local ): Usage, data= [ 0x62 ] 98
                            Internal Failure
            Item(Main  ): Input, data= [ 0xa2 ] 162
                            Data Variable Absolute No_Wrap Linear
                            No_Preferred_State No_Null_Position Volatile Bitfield
            Item(Main  ): Feature, data= [ 0x01 ] 1
                            Constant Array Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): Input, data= [ 0x01 ] 1
                            Constant Array Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x69 ] 105
                            Shutdown  Imminent
            Item(Main  ): Feature, data= [ 0xa2 ] 162
                            Data Variable Absolute No_Wrap Linear
                            No_Preferred_State No_Null_Position Volatile Bitfield
            Item(Local ): Usage, data= [ 0x69 ] 105
                            Shutdown  Imminent
            Item(Main  ): Input, data= [ 0xa2 ] 162
                            Data Variable Absolute No_Wrap Linear
                            No_Preferred_State No_Null_Position Volatile Bitfield
            Item(Global): Report Count, data= [ 0x06 ] 6
            Item(Main  ): Feature, data= [ 0x01 ] 1
                            Constant Array Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): Input, data= [ 0x01 ] 1
                            Constant Array Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Usage Page, data= [ 0x85 ] 133
                            Battery System Page
            Item(Local ): Usage, data= [ 0xd0 ] 208
                            AC Present
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0xa2 ] 162
                            Data Variable Absolute No_Wrap Linear
                            No_Preferred_State No_Null_Position Volatile Bitfield
            Item(Local ): Usage, data= [ 0xd0 ] 208
                            AC Present
            Item(Main  ): Feature, data= [ 0xa2 ] 162
                            Data Variable Absolute No_Wrap Linear
                            No_Preferred_State No_Null_Position Volatile Bitfield
            Item(Main  ): Input, data= [ 0x01 ] 1
                            Constant Array Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): Feature, data= [ 0x01 ] 1
                            Constant Array Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Count, data= [ 0x06 ] 6
            Item(Local ): Usage, data= [ 0x42 ] 66
                            Below Remaining Capacity Limit
            Item(Local ): Usage, data= [ 0x46 ] 70
                            Fully Charged
            Item(Local ): Usage, data= [ 0x44 ] 68
                            Charging
            Item(Local ): Usage, data= [ 0x45 ] 69
                            Discharging
            Item(Local ): Usage, data= [ 0x47 ] 71
                            Fully Discharged
            Item(Local ): Usage, data= [ 0x4b ] 75
                            Need Replacement
            Item(Main  ): Input, data= [ 0xa2 ] 162
                            Data Variable Absolute No_Wrap Linear
                            No_Preferred_State No_Null_Position Volatile Bitfield
            Item(Local ): Usage, data= [ 0x42 ] 66
                            Below Remaining Capacity Limit
            Item(Local ): Usage, data= [ 0x46 ] 70
                            Fully Charged
            Item(Local ): Usage, data= [ 0x44 ] 68
                            Charging
            Item(Local ): Usage, data= [ 0x45 ] 69
                            Discharging
            Item(Local ): Usage, data= [ 0x47 ] 71
                            Fully Discharged
            Item(Local ): Usage, data= [ 0x4b ] 75
                            Need Replacement
            Item(Main  ): Feature, data= [ 0xa2 ] 162
                            Data Variable Absolute No_Wrap Linear
                            No_Preferred_State No_Null_Position Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Report ID, data= [ 0x2a ] 42
            Item(Local ): Usage, data= [ 0x89 ] 137
                            iDeviceChemistry
            Item(Local ): String Index, data= [ 0x04 ] 4
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x62 ] 98
            Item(Local ): Usage, data= [ 0x8f ] 143
                            iOEMInformation
            Item(Local ): String Index, data= [ 0x03 ] 3
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x33 ] 51
            Item(Local ): Usage, data= [ 0x2c ] 44
                            Capacity Mode
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x34 ] 52
            Item(Local ): Usage, data= [ 0x66 ] 102
                            Remaining Capacity
            Item(Main  ): Input, data= [ 0xa2 ] 162
                            Data Variable Absolute No_Wrap Linear
                            No_Preferred_State No_Null_Position Volatile Bitfield
            Item(Local ): Usage, data= [ 0x66 ] 102
                            Remaining Capacity
            Item(Main  ): Feature, data= [ 0xa2 ] 162
                            Data Variable Absolute No_Wrap Linear
                            No_Preferred_State No_Null_Position Volatile Bitfield
            Item(Global): Report ID, data= [ 0x37 ] 55
            Item(Local ): Usage, data= [ 0x67 ] 103
                            Full Charge Capacity
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x36 ] 54
            Item(Local ): Usage, data= [ 0x83 ] 131
                            Design Capacity
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x38 ] 56
            Item(Local ): Usage, data= [ 0x8c ] 140
                            Warning Capacity Limit
            Item(Main  ): Feature, data= [ 0xa2 ] 162
                            Data Variable Absolute No_Wrap Linear
                            No_Preferred_State No_Null_Position Volatile Bitfield
            Item(Global): Report ID, data= [ 0x2c ] 44
            Item(Local ): Usage, data= [ 0x8b ] 139
                            Rechargeable
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x35 ] 53
            Item(Local ): Usage, data= [ 0x68 ] 104
                            Run Time To Empty
            Item(Global): Report Size, data= [ 0x10 ] 16
            Item(Global): Logical Maximum, data= [ 0xff 0xff 0x00 0x00 ] 65535
            Item(Global): Unit, data= [ 0x01 0x10 ] 4097
                            System: SI Linear, Unit: Seconds
            Item(Global): Unit Exponent, data= [ 0x00 ] 0
                            Unit Exponent: 0
            Item(Main  ): Input, data= [ 0xa2 ] 162
                            Data Variable Absolute No_Wrap Linear
                            No_Preferred_State No_Null_Position Volatile Bitfield
            Item(Local ): Usage, data= [ 0x68 ] 104
                            Run Time To Empty
            Item(Main  ): Feature, data= [ 0xa2 ] 162
                            Data Variable Absolute No_Wrap Linear
                            No_Preferred_State No_Null_Position Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Usage Page, data= [ 0x84 ] 132
                            Power Device Page
            Item(Local ): Usage, data= [ 0x10 ] 16
                            Battery System
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Local ): Usage, data= [ 0x12 ] 18
                            Battery
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Report ID, data= [ 0x04 ] 4
            Item(Local ): Usage, data= [ 0x40 ] 64
                            Config Voltage
            Item(Global): Unit, data= [ 0x21 0xd1 0xf0 0x00 ] 15782177
                            System: SI Linear, Unit: Centimeter^2*Gram*Seconds^-3*Ampere^-1
            Item(Global): Unit Exponent, data= [ 0x07 ] 7
                            Unit Exponent: 7
            Item(Main  ): Feature, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x20 ] 32
            Item(Local ): Usage, data= [ 0x30 ] 48
                            Voltage
            Item(Global): Unit, data= [ 0x21 0xd1 0xf0 0x00 ] 15782177
                            System: SI Linear, Unit: Centimeter^2*Gram*Seconds^-3*Ampere^-1
            Item(Global): Unit Exponent, data= [ 0x01 ] 1
                            Unit Exponent: 1
            Item(Main  ): Feature, data= [ 0xa2 ] 162
                            Data Variable Absolute No_Wrap Linear
                            No_Preferred_State No_Null_Position Volatile Bitfield
            Item(Local ): Usage, data= [ 0x02 ] 2
                            Present Status
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Report ID, data= [ 0x23 ] 35
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x02 ] 2
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Unit, data= [ 0x00 ] 0
                            System: None, Unit: (None)
            Item(Global): Unit Exponent, data= [ 0x00 ] 0
                            Unit Exponent: 0
            Item(Main  ): Feature, data= [ 0x01 ] 1
                            Constant Array Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Count, data= [ 0x06 ] 6
            Item(Global): Usage Page, data= [ 0x85 ] 133
                            Battery System Page
            Item(Local ): Usage, data= [ 0x42 ] 66
                            Below Remaining Capacity Limit
            Item(Local ): Usage, data= [ 0x46 ] 70
                            Fully Charged
            Item(Local ): Usage, data= [ 0x44 ] 68
                            Charging
            Item(Local ): Usage, data= [ 0x45 ] 69
                            Discharging
            Item(Local ): Usage, data= [ 0x47 ] 71
                            Fully Discharged
            Item(Local ): Usage, data= [ 0x4b ] 75
                            Need Replacement
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Report ID, data= [ 0x21 ] 33
            Item(Local ): Usage, data= [ 0x66 ] 102
                            Remaining Capacity
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Logical Maximum, data= [ 0x64 ] 100
            Item(Main  ): Feature, data= [ 0xa2 ] 162
                            Data Variable Absolute No_Wrap Linear
                            No_Preferred_State No_Null_Position Volatile Bitfield
            Item(Global): Report ID, data= [ 0x10 ] 16
            Item(Global): Usage Page, data= [ 0x84 ] 132
                            Power Device Page
            Item(Local ): Usage, data= [ 0x58 ] 88
                            Test
            Item(Global): Logical Maximum, data= [ 0x06 ] 6
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Main  ): End Collection, data=none
            Item(Local ): Usage, data= [ 0x1e ] 30
                            Flow
            Item(Main  ): Collection, data= [ 0x00 ] 0
                            Physical
            Item(Global): Report ID, data= [ 0x01 ] 1
            Item(Local ): Usage, data= [ 0x40 ] 64
                            Config Voltage
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Unit, data= [ 0x21 0xd1 0xf0 0x00 ] 15782177
                            System: SI Linear, Unit: Centimeter^2*Gram*Seconds^-3*Ampere^-1
            Item(Global): Unit Exponent, data= [ 0x07 ] 7
                            Unit Exponent: 7
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x02 ] 2
            Item(Local ): Usage, data= [ 0x42 ] 66
                            Config Frequency
            Item(Global): Unit, data= [ 0x01 0xf0 ] 61441
                            System: SI Linear, Unit: Seconds^-1
            Item(Global): Unit Exponent, data= [ 0x00 ] 0
                            Unit Exponent: 0
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x03 ] 3
            Item(Local ): Usage, data= [ 0x43 ] 67
                            Config Apparent Power
            Item(Global): Report Size, data= [ 0x10 ] 16
            Item(Global): Logical Maximum, data= [ 0xff 0xff 0x00 0x00 ] 65535
            Item(Global): Unit, data= [ 0x21 0xd1 ] 53537
                            System: SI Linear, Unit: Centimeter^2*Gram*Seconds^-3
            Item(Global): Unit Exponent, data= [ 0x07 ] 7
                            Unit Exponent: 7
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Local ): Usage, data= [ 0x16 ] 22
                            Power Converter
            Item(Main  ): Collection, data= [ 0x00 ] 0
                            Physical
            Item(Local ): Usage, data= [ 0x1a ] 26
                            Input
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Report ID, data= [ 0x18 ] 24
            Item(Local ): Usage, data= [ 0x30 ] 48
                            Voltage
            Item(Global): Unit, data= [ 0x21 0xd1 0xf0 0x00 ] 15782177
                            System: SI Linear, Unit: Centimeter^2*Gram*Seconds^-3*Ampere^-1
            Item(Global): Unit Exponent, data= [ 0x01 ] 1
                            Unit Exponent: 1
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Global): Report ID, data= [ 0x19 ] 25
            Item(Local ): Usage, data= [ 0x32 ] 50
                            Frequency
            Item(Global): Unit, data= [ 0x01 0xf0 ] 61441
                            System: SI Linear, Unit: Seconds^-1
            Item(Global): Unit Exponent, data= [ 0x01 ] 1
                            Unit Exponent: 1
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Local ): Usage, data= [ 0x1c ] 28
                            Output
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Report ID, data= [ 0x1b ] 27
            Item(Local ): Usage, data= [ 0x30 ] 48
                            Voltage
            Item(Global): Unit, data= [ 0x21 0xd1 0xf0 0x00 ] 15782177
                            System: SI Linear, Unit: Centimeter^2*Gram*Seconds^-3*Ampere^-1
            Item(Global): Unit Exponent, data= [ 0x01 ] 1
                            Unit Exponent: 1
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Global): Report ID, data= [ 0x1c ] 28
            Item(Local ): Usage, data= [ 0x32 ] 50
                            Frequency
            Item(Global): Unit, data= [ 0x01 0xf0 ] 61441
                            System: SI Linear, Unit: Seconds^-1
            Item(Global): Unit Exponent, data= [ 0x01 ] 1
                            Unit Exponent: 1
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Local ): Usage, data= [ 0x02 ] 2
                            Present Status
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Report ID, data= [ 0x22 ] 34
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x03 ] 3
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Unit, data= [ 0x00 ] 0
                            System: None, Unit: (None)
            Item(Global): Unit Exponent, data= [ 0x00 ] 0
                            Unit Exponent: 0
            Item(Local ): Usage, data= [ 0x63 ] 99
                            Voltage out of range
            Item(Local ): Usage, data= [ 0x6f ] 111
                            Buck
            Item(Local ): Usage, data= [ 0x6e ] 110
                            Boost
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x65 ] 101
                            Overload
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Local ): Usage, data= [ 0x6d ] 109
                            Used
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x67 ] 103
                            Over Temperature
            Item(Local ): Usage, data= [ 0x62 ] 98
                            Internal Failure
            Item(Global): Report Count, data= [ 0x02 ] 2
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Global): Report Count, data= [ 0x06 ] 6
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Local ): Usage, data= [ 0x72 ] 114
                            Awaiting Power
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Main  ): Feature, data= [ 0x01 ] 1
                            Constant Array Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Main  ): End Collection, data=none
            Item(Local ): Usage, data= [ 0x18 ] 24
                            Outlet System
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Local ): Usage, data= [ 0x20 ] 32
                            Outlet
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Report ID, data= [ 0x15 ] 21
            Item(Local ): Usage, data= [ 0x57 ] 87
                            Delay Before Shutdown
            Item(Global): Report Size, data= [ 0x10 ] 16
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Logical Maximum, data= [ 0xff 0xff 0x00 0x00 ] 65535
            Item(Global): Unit, data= [ 0x01 0x10 ] 4097
                            System: SI Linear, Unit: Seconds
            Item(Global): Unit Exponent, data= [ 0x00 ] 0
                            Unit Exponent: 0
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Global): Usage Page, data= [ 0x84 ] 132
                            Power Device Page
            Item(Global): Report ID, data= [ 0x17 ] 23
            Item(Local ): Usage, data= [ 0x55 ] 85
                            Delay Before Reboot
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0xff 0xff 0x00 0x00 ] 65535
            Item(Global): Physical Minimum, data= [ 0x00 ] 0
            Item(Global): Physical Maximum, data= [ 0x00 ] 0
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Global): Report ID, data= [ 0x1e ] 30
            Item(Local ): Usage, data= [ 0x35 ] 53
                            Percent Load
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Unit, data= [ 0x00 ] 0
                            System: None, Unit: (None)
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Global): Usage Page, data= [ 0xff 0xff ] 65535
                            (null)
            Item(Global): Report ID, data= [ 0x51 ] 81
            Item(Local ): Usage, data= [ 0x91 ] 145
                            (null)
            Item(Global): Unit, data= [ 0x00 ] 0
                            System: None, Unit: (None)
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Main  ): End Collection, data=none
            Item(Global): Usage Page, data= [ 0xff 0xff ] 65535
                            (null)
            Item(Local ): Usage, data= [ 0xfe ] 254
                            (null)
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Report ID, data= [ 0x0d ] 13
            Item(Local ): Usage, data= [ 0x75 ] 117
                            (null)
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x0e ] 14
            Item(Local ): Usage, data= [ 0x76 ] 118
                            (null)
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x0f ] 15
            Item(Local ): Usage, data= [ 0x7c ] 124
                            (null)
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Global): Report ID, data= [ 0x43 ] 67
            Item(Local ): Usage, data= [ 0x9c ] 156
                            (null)
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Main  ): Feature, data= [ 0x82 ] 130
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Volatile Bitfield
            Item(Global): Report ID, data= [ 0x6c ] 108
            Item(Local ): Usage, data= [ 0x7d ] 125
                            (null)
            Item(Global): Report Size, data= [ 0x10 ] 16
            Item(Global): Logical Maximum, data= [ 0xff 0xff 0x00 0x00 ] 65535
            Item(Main  ): Feature, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Main  ): End Collection, data=none
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               8
Device Status:     0x0003
  Self Powered
  Remote Wakeup Enabled

@jimklimov
Copy link
Member

jimklimov commented Mar 1, 2024

Thanks for the confirmation! Could you please check if it would also work without the (partial) changes from @x0ul that you've outlined above, just using the driver configuration options?

Namely, I think the critical change was { USB_DEVICE(LIEBERT_VENDORID, 0x0002), NULL }, to match the driver - nowadays usbhid-ups has a subdriver option to force the handling of specified vendorid+productid at run-time.

The effective removal of belkin_usage_lkp seems a bit counter-productive in a driver for Belkin devices, that's the change I am most interested in (or rather, if stuff would still work with this table back in place - or what would break?) :)

Finally, the hid_* settings can be set as driver options with the code from my PR yesterday:

        case SUPPORTED:
+               usb->hid_rep_index = 1;
+               usb->hid_desc_index = 1;

I suppose the driver testing command (for code built from just my PR'ed branch) would look like this to run once, dump the data, and exit:

:; usbhid-ups -s testups -x port=auto -x vendorid=10af -x productid=0002 -x usb_hid_rep_index=1 -x usb_hid_desc_index=1 -x subdriver="Belkin/Liebert" -d1

(with normal driver service stopped, so the device is available for grabs).

Also maybe let it run for a few data collection loops before exiting, with a larger -d NUM option.

@jrjparks
Copy link
Contributor

jrjparks commented Mar 1, 2024

I probably should have clarified I only added { USB_DEVICE(LIEBERT_VENDORID, 0x0002), NULL },, but removing that change and only using what is in issue-2149 it still working.

diff --git a/drivers/belkin-hid.c b/drivers/belkin-hid.c
index 686dc9261..46cfddf0c 100644
--- a/drivers/belkin-hid.c
+++ b/drivers/belkin-hid.c
@@ -71,6 +73,8 @@ static usb_device_id_t belkin_usb_device_table[] = {
        { USB_DEVICE(LIEBERT_VENDORID, 0x0004), NULL },
        /* Liebert PowerSure PSA UPS */
        { USB_DEVICE(LIEBERT_VENDORID, 0x0001), NULL },
+       /* Liebert PowerSure PST UPS */
+       { USB_DEVICE(LIEBERT_VENDORID, 0x0002), NULL },
        /* Liebert PowerSure PSI 1440 */
        { USB_DEVICE(LIEBERT_VENDORID, 0x0004), NULL },
        /* Liebert GXT3 */
@@ -424,7 +428,7 @@ static usage_lkp_t belkin_usage_lkp[] = {
 };

I did need to include -x pollonly=enabled

$ sudo ./drivers/usbhid-ups -s UPS-1 -x port=auto -x vendorid=10af -x productid=0002 -x usb_hid_rep_index=1 -x usb_hid_desc_index=1 -x subdriver="Be
lkin/Liebert" -d1
Network UPS Tools - Generic HID driver 0.52 (2.8.0-3661-gbe6534e5d)
USB communication driver (libusb 1.0) 0.46
Using subdriver: Belkin/Liebert HID 0.18
nut_libusb_get_interrupt: Input/Output Error
$ sudo ./drivers/usbhid-ups -s UPS-1 -x port=auto -x vendorid=10af -x productid=0002 -x usb_hid_rep_index=1 -x usb_hid_desc_index=1 -x subdriver="Be
lkin/Liebert" -x pollonly=enabled -d1
Network UPS Tools - Generic HID driver 0.52 (2.8.0-3661-gbe6534e5d)
USB communication driver (libusb 1.0) 0.46
Using subdriver: Belkin/Liebert HID 0.18

@jimklimov
Copy link
Member

Super! Thanks!

@jimklimov jimklimov added this to the 2.8.2 milestone Mar 1, 2024
@jimklimov
Copy link
Member

Relevant PRs were merged to master by now, so "standard" text of https://github.com/networkupstools/nut/wiki/Building-NUT-for-in%E2%80%90place-upgrades-or-non%E2%80%90disruptive-tests would apply for testing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement impacts-release-2.7.3-or-older Issues reported against NUT release 2.7.3 or older, packaged or custom builds of code from that era impacts-release-2.7.4 Issues reported against NUT release 2.7.4 (maybe vanilla or with minor packaging tweaks) impacts-release-2.8.0 Issues reported against NUT release 2.8.0 (maybe vanilla or with minor packaging tweaks) USB non-zero interface numbers Most UPSes serve USB interactions on interface 0 which is default. Recent "composite devices" differ USB
Projects
None yet
Development

No branches or pull requests

5 participants