Rob Groner
2014-Mar-07 16:24 UTC
[Nut-upsdev] Developing the UPS side of the UPS-NUT equation (via usbhid)
Charles, Thank you so much for the information. I'm trying to digest it along with the other docs I have, the example code from Microchip, and a USB HID tutorial I found online. So, if I understand correctly.... When the device first connects, it sends a huge dump of data (which the usbhid driver shows when you use the debug option) which fully describes the data it is capable of sending. The usage id's, pages, etc use values from the USBHID spec, but the actual data can be defined as needed by the device (in terms of width and ranges), and then the device assigns an arbitrary (but I'm assuming unique) report ID to the description so that when it needs to send the data, it can do so simply with a Report ID and the described data. Am I getting close to the truth? Rob -----Original Message----- From: Charles Lepple [mailto:clepple at gmail.com] Sent: Thursday, March 06, 2014 11:02 PM To: Rob Groner Cc: nut-upsdev at lists.alioth.debian.org Subject: Re: [Nut-upsdev] Developing the UPS side of the UPS-NUT equation (via usbhid) On Mar 6, 2014, at 3:55 PM, Rob Groner wrote:> To make this UPS as easy to use as possible for the end-user who chooses Linux, I figured I would just completely implement the official USB HID UPS spec. That way no subdriver would be needed, or at least very little.At the moment, we use USB VID and PID to select which HID-to-NUT tables to consult (since some vendors have "custom" (incorrect) interpretations of standard HID PDC Usages. So at the very least, you would need a skeleton usbhid-ups subdriver which matches your VID:PID combination.>From there, though, if you follow the standard HID PDC Usage IDs, you should be able to just map the "HID path" (see below) to the corresponding NUT name.> However, I am having a terrible time making sense of the pages in the NUT guide for writing USB HID drivers, and the USB HID usage table at usb.org. Just looking at some of the report ID values that I KNOW are working from the UPS example running on the microchip, I can't seem to find their equivalent in either doc. For instance, I know that the UPS code is sending status info using a Report ID of 0x40 and two bytes of data...but I cannot find anything in the usb.org docs that relates to this. NUT somehow understands it, though, since it correctly reports the device's status.The report IDs aren't standardized - the HID Usage IDs are. The Report ID is essentially an opaque, small number to avoid having to send a full list of HID Usage IDs every time a new report is ready. If you look up Report ID 0x40 in your HID Report Descriptor, you should see a few HID Usage Pages and HID Usage IDs. Usage Pages are just the upper 16 bits of a full Usage ID as seen in the drivers. In the HID Report Descriptor, the Usage Pages and Usages will most likely be represented as hexadecimal. At the end of drivers/libhid.c (hid_usage_lkp[]) is a set of tables that map names to 32-bit hex Usage Page/Usage pairs. Another slightly strange concept in NUT is the way that HID Collections are represented. Each collection has a Usage Page/Usage associated with it, and for an UPS, these generally start with Page 0x84 (UPS) or Page 0x85 (Battery). They are separated with dots, and the whole thing is termed a "HID path" or similar. Let's use "UPS.PowerConverter.Output.Voltage" from an MGE Evolution as an example.>From lsusb -vvv (run as root; with the Linux kernel HID driver detached if applicable, and the NUT driver stopped):Report Descriptor: (length is 1300) ... Item(Global): Usage Page, data= [ 0x84 ] 132 Power Device Page Item(Local ): Usage, data= [ 0x04 ] 4 UPS Item(Main ): Collection, data= [ 0x00 ] 0 Physical ... Item(Local ): Usage, data= [ 0x16 ] 22 Power Converter Item(Main ): Collection, data= [ 0x00 ] 0 Physical ... Item(Local ): Usage, data= [ 0x1c ] 28 Output Item(Main ): Collection, data= [ 0x00 ] 0 Physical ... Item(Global): Report ID, data= [ 0x1c ] 28 ... Item(Local ): Usage, data= [ 0x30 ] 48 Voltage Moving backwards from Voltage, we see that the Report ID is 0x1c. By summing up the size of the features in that Report (the Report size is "sticky" in that it is only specified when it changes between fields), we can find the offset and size of the voltage field. (Sizes are in bits.) I'll let the usbhid-ups driver do the dirty work: 5.648610 Report[buf]: (10 bytes) => 1c 01 04 57 00 49 00 77 00 3b 5.648687 Path: UPS.PowerConverter.Output.Voltage, Type: Feature, ReportID: 0x1c, Offset: 48, Size: 16, Value: 119 So an offset of 48 (counting past the report ID 0x1c at the beginning of the buffer) is 48/8 = 6 bytes in, for a value of "77 00" (0x0077 since USB is little-endian), or 119. -- Charles Lepple clepple at gmail
Charles Lepple
2014-Mar-08 00:03 UTC
[Nut-upsdev] Developing the UPS side of the UPS-NUT equation (via usbhid)
On Mar 7, 2014, at 11:24 AM, Rob Groner wrote:> Charles, > > Thank you so much for the information. I'm trying to digest it along with the other docs I have, the example code from Microchip, and a USB HID tutorial I found online.I realize that some of the descriptions can be a bit vague, so if you want to post a link to the HID tutorial, I can try to describe what is going on there.> So, if I understand correctly.... When the device first connects, it sends a huge dump of data(the HID Report Descriptor)> (which the usbhid driver shows when you use the debug option) which fully describes the data it is capable of sending.Correct. At some point, the usbhid-ups driver starts asking the UPS for reports corresponding to the variables it needs, but that initial traffic is from reading the HID Report Descriptor, then looking up the report IDs from the parsed descriptor.> The usage id's, pages, etc use values from the USBHID spec, but the actual data can be defined as needed by the device (in terms of width and ranges), and then the device assigns an arbitrary (but I'm assuming unique) report ID to the description so that when it needs to send the data, it can do so simply with a Report ID and the described data.That's it. -- Charles Lepple clepple at gmail
Rob Groner
2014-Mar-08 14:40 UTC
[Nut-upsdev] Developing the UPS side of the UPS-NUT equation (via usbhid)
Thank you! It is nice to have some confirmation that I'm on the right track. The tutorial was pretty helpful, though it deferred some of the definitions to referencing the HID documents. I don't really have any questions about that, but I'll post the link for others in case they come upon this thread later. http://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/ I found the HID report descriptor that the Microchip controller assembles in code, and they did a good job of documenting each line, so I'm going to do some experimentation with putting together my own descriptor from that. I'm still a little foggy on the proper use of collections, but the top level HID docs at usb.org are turning out to be almost understandable now. http://www.usb.org/developers/devclass_docs/HID1_11.pdf I think I have the general idea now, which is comforting because I was completely dumbfounded just a few days ago. I'll post more specific questions as they come. Thanks again! Rob -----Original Message----- From: Charles Lepple [mailto:clepple at gmail.com] Sent: Friday, March 07, 2014 7:04 PM To: Rob Groner Cc: nut-upsdev at lists.alioth.debian.org Subject: Re: [Nut-upsdev] Developing the UPS side of the UPS-NUT equation (via usbhid) On Mar 7, 2014, at 11:24 AM, Rob Groner wrote:> Charles, > > Thank you so much for the information. I'm trying to digest it along with the other docs I have, the example code from Microchip, and a USB HID tutorial I found online.I realize that some of the descriptions can be a bit vague, so if you want to post a link to the HID tutorial, I can try to describe what is going on there.> So, if I understand correctly.... When the device first connects, it sends a huge dump of data(the HID Report Descriptor)> (which the usbhid driver shows when you use the debug option) which fully describes the data it is capable of sending.Correct. At some point, the usbhid-ups driver starts asking the UPS for reports corresponding to the variables it needs, but that initial traffic is from reading the HID Report Descriptor, then looking up the report IDs from the parsed descriptor.> The usage id's, pages, etc use values from the USBHID spec, but the actual data can be defined as needed by the device (in terms of width and ranges), and then the device assigns an arbitrary (but I'm assuming unique) report ID to the description so that when it needs to send the data, it can do so simply with a Report ID and the described data.That's it. -- Charles Lepple clepple at gmail
Possibly Parallel Threads
- Developing the UPS side of the UPS-NUT equation (via usbhid)
- Developing the UPS side of the UPS-NUT equation (via usbhid)
- Developing the UPS side of the UPS-NUT equation (via usbhid)
- Developing the UPS side of the UPS-NUT equation (via usbhid)
- Developing the UPS side of the UPS-NUT equation (via usbhid)