[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