[Nut-upsdev] [nut-upsuser] Copeland Engineering Dockmaster
Charles Lepple
clepple at gmail.com
Sun Mar 19 22:49:53 UTC 2017
On Mar 19, 2017, at 10:56 AM, Drew from Zhrodague <drewzhrodague at zhrodague.net> wrote:
>
> [] I've spoken with one of the developers, and he's offered to share some technical documentation with me. I'll report here with whatever I can. He's on vacation in China.
Hopefully this documentation will lead to fewer surprises down the road.
> [] I found this hid-example.c program, which fetches the values from the unit, including a timer, and a current state. However, this example program pushes data into the unit (to test writing), which sets the timers to astronomical values. I am not sure the format it wants, I'm unable to actually set anything, and the timer seems to default to 'a3 minutes'. My C is rusty, but commenting-out the writing portion makes the data collection not work.
I keep finding the generic hid-example.c from the Linux kernel tree when searching - do you have one specifically for this device?
>
> [] After unloading the hid modules, I was able to get more details on the USB format, and I am trying to read documentation to understand what's going on. From lsusb -vvv:
>
> Report Descriptor: (length is 34)
> Item(Global): Usage Page, data= [ 0xa0 0xff ] 65440
> (null)
> Item(Local ): Usage, data= [ 0xa5 ] 165
> (null)
> Item(Main ): Collection, data= [ 0x01 ] 1
> Application
> Item(Local ): Usage, data= [ 0xa6 ] 166
> (null)
> Item(Local ): Usage, data= [ 0xa7 ] 167
> (null)
> Item(Global): Logical Minimum, data= [ 0x00 ] 0
> Item(Global): Logical Maximum, data= [ 0xff ] 255
> Item(Global): Report Size, data= [ 0x08 ] 8
> Item(Global): Report Count, data= [ 0x08 ] 8
> Item(Main ): Input, data= [ 0x02 ] 2
> Data Variable Absolute No_Wrap Linear
> Preferred_State No_Null_Position Non_Volatile Bitfield
This is the decoded version of roughly the first half of the Report Descriptor bytes below. The HID Report Descriptor has an obscure stack-based approach to organizing data. Both collections and individual Input/Output/Feature items are "named" with Usage numbers, and the Usage Page is a way to set the top 16 bits of the Usage number.
The problem here is that the Usage Page is 0xFFA0, and IDs beginning with 0xFF are vendor-specific. (For an UPS, this would be something like 0x84 for the Power Device Page. See /usr/share/misc/usb.ids after the VID/PID section.)
I think this one byte (Report Size == 8 bits) for Usage 0xA6, and the other seven bytes (left over from Report Count == 8 x 8 bits) for usage 0xA7. Logical Minimum and Logical Maximum of 0 and 255 tell us that the bytes are unsigned, but that is typical for just passing things through the HID APIs. (A mouse would use signed values for the X and Y axes, for instance.)
> Item(Local ): Usage, data= [ 0xa9 ] 169
> (null)
> Item(Global): Logical Minimum, data= [ 0x00 ] 0
> Item(Global): Logical Maximum, data= [ 0xff ] 255
> Item(Global): Report Size, data= [ 0x08 ] 8
> Item(Global): Report Count, data= [ 0x08 ] 8
> Item(Main ): Output, data= [ 0x02 ] 2
> Data Variable Absolute No_Wrap Linear
> Preferred_State No_Null_Position Non_Volatile Bitfield
> Item(Main ): End Collection, data=none
This is the part that is being written to - 0xA9 is an 8-byte output field. As with the Input items earlier, the microcontroller is free to interpret these bytes in any way, so there might be fields within that.
> 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 10
Exact values usually don't matter here, but 8 bytes is a typical wMaxPacketSize, especially for lower-speed USB devices.
> This is from the hid-example.c:
>
> Report Descriptor:
> 6 a0 ff 9 a5 a1 1 9 a6 9 a7 15 0 25 ff 75 8 95 8 81 2 9 a9 15 0 25 ff 75 8 95 8 91 2 c0
>
I mistyped earlier:
> * Use libhid, which involves detaching the hiddev/hidraw driver from the device. We do this all the time with PDC HID devices. It might take a little more experimenting to find the libusb command to send.
should be "Use libusb..." - at one point, there was a libhid that used libusb, but part of that got absorbed into NUT.
I started modifying one of the drivers to do the reads, but it may not be of much use until we understand what needs to be written, as you mentioned here:
> but commenting-out the writing portion makes the data collection not work.
More information about the Nut-upsdev
mailing list