Related
I'm implementing a custom HID device that has the following interface:
0x06, 0xA0, 0xFF, // Usage Page (Vendor Defined 0xFFA0)
0x09, 0x01, // Usage (0x01)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x15, 0x00, // Logical Minimum (0)
0x26, 0x01, 0x00, // Logical Maximum (1)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x01, // Report ID (1)
0x15, 0x00, // Logical Minimum (0)
0x26, 0x01, 0x00, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x02, // Report Count (2)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x06, // Report Size (6)
0x95, 0x01, // Report Count (1)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x85, 0x03, // Report ID (1)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0xFF, // Logical Maximum (65535)
0x75, 0x10, // Report Size (16)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
When I plug this device into the computer through a USB logic analyzer I see it enumerate, then something (I'm not sure what, any ideas?) uses the HID report descriptor to intelligently grab a bunch of reports:
(control)(endpoint 0) Get Input Report[1]
(control)(endpoint 0) Get Feature Report[1]
The "Get Input Report" entry confused me as I thought input reports were sent via an interrupt transfer. If I use usbhid's hid_write, I see the following entry, so I must be at least half right about input reports being sent via interrupt transfers...:
(interrupt)(endpoint 1) Input Report[1]"
I have been unable to find information that describes the difference between control "get input reports" and interrupt "input report" transfers which I am hoping one of you will know about.
Why do control "get input reports" exist?
Why not just have the spec mandate a "get feature report" entry exist for every "input report" id entry?
Why is whatever is grabbing input/feature reports for every defined input/feature report using a control transfer for the input reports vs. an interrupt transfer?
Have a look at USB HID v1.1. There is definition for Get_Report request on page 51:
This request is useful at initialization time for absolute items and for determining the state of feature items. This request is not intended to be used for polling the device state on a regular basis.
Here, this is exactly what the driver is doing: it is retrieving the various reports to initialize its current state. Note the host cannot request the device to send a report on its interrupt pipe. Hence the request on control pipe.
Chapter 4.4 explains various endpoints usage.
Also note feature reports and input reports do not address the same data, even if they have the same report ID (report IDs are per report type).
For the past two weeks I have been trying to configure my card (STM32F4) to dialogue with USB HID with a PC under Windows 7. I make success with this descriptor:
__ALIGN_BEGIN static uint8_t HID_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
0x06, 0xFF, 0x00, // USAGE_PAGE (Vendor Page: 0xFF00)
0x09, 0x01, // USAGE (Demo Kit)
0xa1, 0x01, // COLLECTION (Application)
//0x85, 0x01, // REPORT_ID (1)
0x09, 0x02, // USAGE (DATA)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff,0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x04, // REPORT_COUNT (4)
0x81, 0x02, // INPUT (Data,Var,Abs,Vol)
0xc0 // END_COLLECTION
};
Like this, Windows recognizeS my card like a compliant HID component.
Now if I want to send 32 bit data like a uint32, Windows recognizes the card, but it sees an error to tell that it can't start it! My descriptor:
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
0x06, 0xFF, 0x00, // USAGE_PAGE (Vendor Page: 0xFF00)
0x09, 0x01, // USAGE (Demo Kit)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x02, // USAGE (DATA)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x27, 0xff,0xff,0xff,0xff, // LOGICAL_MAXIMUM (65535)
0x75, 0x20, // REPORT_SIZE (32)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs,Vol)
0xc0 // END_COLLECTION
};
I didn't understand why it din't work!
After that, I use USBlyser to scan my other USB device on my PC, and I take this descriptor about my spacespilot 3D mouse:
Endpoint Descriptor 83 3 In, Interrupt, 16 ms
Offset Field Size Value Description
0 bLength 1 07h
1 bDescriptorType 1 05h Endpoint
2 bEndpointAddress 1 83h 3 In
3 bmAttributes 1 03h Interrupt
1..0: Transfer Type ......11 Interrupt
7..2: Reserved 000000..
4 wMaxPacketSize 2 0007h 7 bytes
6 bInterval 1 08h 16 ms
Interface 1 HID Report Descriptor Multi-Axis Controller
Item Tag (Value) Raw Data
Usage Page (Generic Desktop) 05 01
Usage (Multi-Axis Controller) 09 08
Collection (Application) A1 01
Collection (Physical) A1 00
Report ID (1) 85 01
Logical Minimum (-500) 16 0C FE
Logical Maximum (500) 26 F4 01
Physical Minimum (-32768) 36 00 80
Physical Maximum (32767) 46 FF 7F
Usage (X) 09 30
Usage (Y) 09 31
Usage (Z) 09 32
Report Size (16) 75 10
Report Count (3) 95 03
Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02
End Collection C0
If I try this, it works fine:
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x08, //Usage (Multi-Axis Controller)
0xa1, 0x01, // COLLECTION (Application)
0xa1, 0x00, // Collection (Physical)
0x85, 0x01, // Report ID (1)
0x16,0x0c,0xfe, // Logical minimum (-500)
0x26,0xf4,0x01, // Logical maximum (500)
0x35,0x00, // Physical Minimum (0)
0x46,0xff,0x00, // Physical Maximum (255)
0x09,0x30, // Usage(X)
0x09,0x31, // Usage(Y)
0x09,0x32, // Usage(Z)
0x09,0x33, // Usage(RX)
0x09,0x34, // Usage(RY)
0x09,0x35, // //Usage(RZ)
0x75, 0x08, // REPORT_SIZE (16)
0x95, 0x06, // REPORT_COUNT (6)
0x81, 0x02, // INPUT (Data,Var,Abs,Vol)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
But if I try the same descriptor that my 3D mouse:
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x08, // Usage (Multi-Axis Controller)
0xa1, 0x01, // COLLECTION (Application)
0xa1, 0x00, // Collection (Physical)
0x85, 0x01, // Report ID (1)
0x16,0x0c,0xfe, // Logical minimum (-500)
0x26,0xf4,0x01, // Logical maximum (500)
0x35,0x00,0x80, // Physical Minimum (-32768)
0x46,0xff,0x7f, // Physical Maximum (32767)
0x09,0x30, // Usage(X)
0x09,0x31, // Usage(Y)
0x09,0x32, // Usage(Z)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x03, // REPORT_COUNT (3)
0x81, 0x02, // INPUT (Data,Var,Abs,Vol)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
Windows gives me the same error, and it can't start the device!!!
What is wrong? Do I need a special driver for Windows to send 32 bit data (int32)? For information, I use the HID library for my application PC side.
How can I resolve this?
The LOGICAL_MAXIMUM four-byte descriptor tag (0x27) is only valid up to 0x7FFFFFFF as it is describing a maximum for a signed int data field. If you want to describe an unsigned int data field you would need to use the LOGICAL_MAXIMUM 8 byte descriptor tag like this:
0x28, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00
Your second example would work, I think. Except for the typo for the Physical maximum descriptor tag. It should be 0x36, not 0x35.
When I tried your last descriptor (using my Arduino USBComposite library for STM32F1), Windows gave me an error about the descriptor having an unknown item. But when I changed the 0x35 in the Physical Minimum line to 0x36, Windows recognized the item.
Alright, I'm building a keyboard with an integrated touch-screen used as a mouse, I'm sending the data generated over BLE via HID OVER GATT. This works fine for org.bluetooth.characteristic.boot_keyboard_input_report & org.bluetooth.characteristic.boot_mouse_input_report, but I'm not very certain how to configure the report_map and what I need to send according to these declarations.
The Main question is really, because there is no hybrid type of Usage, I need to use two Usage. But do I need a second Usage Page? How do you define the Collection (Application) for such a hybrid device?
Usage Page
Usage Keyboard
??Usage Page
Usage Mouse
So I defined my report_map like this:
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x06, // Usage (Keyboard),
0xA1, 0x01, // Collection (Application),
0x05, 0x07, // Usage Page (Key Codes);
0x19, 0xE0, // Usage Minimum (224),
0x29, 0xE7, // Usage Maximum (231),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum (1),
0x75, 0x01, // Report Size (1),
0x95, 0x08, // Report Count (8),
0x81, 0x02, // Input (Data, Variable, Absolute), ; Modifier-Byte 8 bit
0x95, 0x01, // Report Count (1),
0x75, 0x08, // Report Size (8),
0x81, 0x01, // Input (Constant), ; Reserved byte 8 bit
0x95, 0x05, // Report Count (5),
0x75, 0x01, // Report Size (1),
0x05, 0x08, // Usage Page (Page# for LEDs),
0x19, 0x01, // Usage Minimum (1),
0x29, 0x05, // Usage Maximum (5),
0x91, 0x02, // Output (Data, Variable, Absolute), ; LED byte 5 bits
0x95, 0x01, // Report Count (1),
0x75, 0x03, // Report Size (3),
0x91, 0x01, // Output (Constant), ; Padding of 3 bits
0x95, 0x06, // Report Count (6),
0x75, 0x08, // Report Size (8),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x65, // Logical Maximum(101),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0x00, // Usage Minimum (0),
0x29, 0x65, // Usage Maximum (101),
0x81, 0x00, // Input (Data, Array),
0xC0, // End Collection
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x02, // COLLECTION (Logical)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
// ------------------------------ Buttons
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x05, // USAGE_MAXIMUM (Button 5)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x03, // REPORT_COUNT (3)
0x81, 0x02, // INPUT (Data,Var,Abs)
// ------------------------------ Padding
0x75, 0x05, // REPORT_SIZE (5)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
// ------------------------------ X,Y position
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xa1, 0x02, // COLLECTION (Logical)
// ------------------------------ Vertical wheel res multiplier
0x09, 0x48, // USAGE (Resolution Multiplier)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x35, 0x01, // PHYSICAL_MINIMUM (1)
0x45, 0x04, // PHYSICAL_MAXIMUM (4)
0x75, 0x02, // REPORT_SIZE (2)
0x95, 0x01, // REPORT_COUNT (1)
0xa4, // PUSH
0xb1, 0x02, // FEATURE (Data,Var,Abs)
// ------------------------------ Vertical wheel
0x09, 0x38, // USAGE (Wheel)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical
0x45, 0x00, // PHYSICAL_MAXIMUM (0)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xc0, // END_COLLECTION
0xa1, 0x02, // COLLECTION (Logical)
// ------------------------------ Horizontal wheel res multiplier
0x09, 0x48, // USAGE (Resolution Multiplier)
0xb4, // POP
0xb1, 0x02, // FEATURE (Data,Var,Abs)
// ------------------------------ Padding for Feature report
0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical
0x45, 0x00, // PHYSICAL_MAXIMUM (0)
0x75, 0x04, // REPORT_SIZE (4)
0xb1, 0x03, // FEATURE (Cnst,Var,Abs)
// ------------------------------ Horizontal wheel
0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
0x0a, 0x38, 0x02, // USAGE (AC Pan)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
I'm not entirely sure, if I am allowed to define two Usage Pages, or if I need to create a collection and but all of the reports in there.
The second thing I'm not sure of, is how I create the values for specific INPUT Reports. Do they have some numbering system via report-id's that I don't get? Or do they have to be send all at once (I'm guessing this is right).
In my case the reports would look like this:
// Output Report
//
// Byte | D7 D6 D5 D4 D3 D2 D1 D0
// ------+---------------------------------------------------------------------
// 0 | NUM_LOCK CAPS_LOCK SCROLL_LOCK COMPOSE KANA CONSTANT CONSTANT CONSTANT
// Input Report for Keyboard
// Byte | D7 D6 D5 D4 D3 D2 D1 D0
// ------+---------------------------------------------------------------------
// 0 | LEFT_CTRL LEFT_SHIFT LEFT_ALT LEFT_OS RIGHT_CTRL RIGHT_SHIFT RIGHT_ALT RIGHT_OS
// 1 | Reserved please leave at 0
// 2-7 | Keycodes
// Input Report for Pointer
// Byte | D7 D6 D5 D4 D3 D2 D1 D0
// ------+---------------------------------------------------------------------
// 0 | 0 0 0 Forward Back Middle Right Left (Button)
// 1 | X
// 2 | Y
// 3 | Vertical Wheel
// 4 | Horizontal (Tilt) Wheel
Thanks in advance.
I'd like to encode a SHA-256 output (in hex) to give me a 16 character base64 string for password using purposes. base64 appears to not be what I would think it should be. Here's what I want.
(0) "00000000000000000000000000000000" -> "AAAAAAAAAAAAAAAA"
(64) "00000000000000000000000000000040" -> "AAAAAAAAAAAAAABA"
(255) "000000000000000000000000000000ff" -> "AAAAAAAAAAAAAAC/"
(2^16+16) "0000000000000000000000000000100f" -> "AAAAAAAAAAAAAPAP"
heres what I get
base64encode("00000000000000000000000000000000")
"MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAA"
This result is consistent with online converters, using R, etc.,
so obviously base64 is not what I think it is and I'm trying to do something else. If I'm not trying to "encode in base 64", what am I trying to do?
My favorite is:
> base64encode(64)
[1] "AAAAAAAAUEA="
> base64encode("64")
[1] "NjQA"
which just baffles me
Base64 works on byte arrays, so in your example, base64encode("00000000000000000000000000000000") is encoding the string value "000...", as a byte array. Since the byte value for the character "0" is 0x30, you're essentially encoding a byte array consisting of 32 0x30 bytes (and by the looks of it, a null terminator (0x00) at the end).
If you're trying to get a 16 character output, you need to encode a 12 byte input (since Base64 produces 4 characters of output for 3 bytes of input), e.g. (You don't give the language, so I'm guessing at the syntax for byte arrays as { 0x.., 0x.., ... }):
base64encode({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
= "AAAAAAAAAAAAAAAA"
base64encode({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})
= "AAAAAAAAAAAAAAAB"
base64encode({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40})
= "AAAAAAAAAAAAAABA"
etc...
The SHA-xxx algorithms should naturally produce a byte-array output, so you should be able to take the appropriate number of bytes from it, and pass them to base64encode. If your SHA method produces a hex string output, then you'll need to convert the hex string back to a byte array before passing Base64 encoding.
To use the beagleboard xm as an HID peripheral I plan to do the following:
Discover how to build things with angstrom.
Get the kernel source 2.6.32.
Compile omap_udc and g_hid
Insert those modules into the kernel
Compile the example from gadget_hid.txt
Send keyboard commands with hid_gadget_test /dev/hidg0 keyboard
Is that a good way to do what I want?
http://www.edaboard.com/thread145675.html is a somewhat related issue from '09.
Looking for Example Embedded Linux HID Device Code is very similar.
I figured I would post this here because I looked and looked for an answer but to no avail so I had to get creative.
First
Go here and get the Kernel
http://eewiki.net/display/linuxonarm/BeagleBone
Second in
The KERNEL/arch/arm/mach-omap2/board-am335xevm.c
Add:
enter code here
#include <linux/usb/g_hid.h>
/* hid descriptor for a keyboard */
static struct hidg_func_descriptor my_hid_data = {
.subclass = 0, /* No subclass */
.protocol = 1, /* Keyboard */
.report_length = 8,
.report_desc_length = 63,
.report_desc = {
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
0x09, 0x06, /* USAGE (Keyboard) */
0xa1, 0x01, /* COLLECTION (Application) */
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x95, 0x08, /* REPORT_COUNT (8) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
0x95, 0x05, /* REPORT_COUNT (5) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x05, 0x08, /* USAGE_PAGE (LEDs) */
0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */
0x29, 0x05, /* USAGE_MAXIMUM (Kana) */
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x03, /* REPORT_SIZE (3) */
0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
0x95, 0x06, /* REPORT_COUNT (6) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x65, /* LOGICAL_MAXIMUM (101) */
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
0x19, 0x00, /* USAGE_MINIMUM (Reserved) */
0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */
0x81, 0x00, /* INPUT (Data,Ary,Abs) */
0xc0 /* END_COLLECTION */
}
};
static struct platform_device my_hid = {
.name = "hidg",
.id = 0,
.num_resources = 0,
.resource = 0,
.dev = {
.platform_data = &my_hid_data,
},
};
static void __init am33xx_hidg_init(void)
{
int ret;
ret = platform_device_register(&my_hid);
if (ret)
printk("HID Gadget registration failed\n");
}
In the:
static void __init am335x_evm_init(void)
{
am33xx_cpuidle_init();
am33xx_mux_init(board_mux);
omap_serial_init();
am335x_rtc_init();
**am33xx_hidg_init();**
clkout2_enable();
}
Build the kernel following the Guide from earlier
In the makemenu config section of the kernel build
go to the device drivers->usb support-> USB Gadget Support-> USB Gadget Drivers -> Compile HID Gadget as Module ( you may have to hunt for it but it's around this section in a couple more sub menus)
Take the sample code section from the kernel documentation
or this page http://www.mjmwired.net/kernel/Documentation/usb/gadget_hid.txt
Compile with GCC
insmod the g_hid.ko driver
and then run the compiled sample code