I'm having another issue, I'm building a HID device (Joystick) that uses Rx, Ry, Rz and in some point I need to do a calibration on the device side. I need to send data from PC(Host) to the device and back for this calibration purpose using custom PC client software and I'm willing to use FEATURE report, which I think is suitable for this purpose.
My INPUT report handling the Rx, Ry, Rz axes works with no problem. I'm sending 3 16-bit (total of 6 bytes) values into the device and it works perfectly.
But I'm having trouble with the FEATURE report, I searched like half the internet already but couldn't manage to get the FEATURE reports to work. I'm using HIDAPITESTER command line tool for the testing purposes. I need to send data from-to host when I need to. As to my information, FEATURE reports are right for this purpose, they are controlled from the host side and are bidirectional. The data contained will be always the same - 64-bytes of data (I actually need only 38 bytes).
I really think that the only problem is with my report descriptor, could you advise on what I'm doing wrong?
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x09, 0x33, // Usage (Rx)
0x09, 0x34, // Usage (Ry)
0x09, 0x35, // Usage (Rz)
0x15, 0x00, // Logical Minimum (0)
0x26, 0x00, 0x10, // Logical Maximum (4096)
0x75, 0x10, // Report Size (16)
0x95, 0x03, // Report Count (3)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x00, // Usage (Undefined)
0x15, 0x00, // Logical Minimum (0)
0x26, 0x00, 0x10, // Logical Maximum (4096)
0x75, 0x10, // Report Size (16)
0x95, 0x20, // Report Count (32)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
I have tried another report descriptors, but they always resulted in not being able to enumerate.
The USB stack I'm using is M-Stack.
I'm using endpoints 0x81 for IN and 0x01 for OUT packets.
The device is PIC18F2458 but I don't think this has any thing to do with this issue really.
Thank you for any valuable help, I'm really desperate for past two days already.
I would like to emulate 3M USB touchscreen controller. I found exact protocol and slightly changed the source code in teensy3 library. I changed VendorID and ProductID. Also I added my USB isr handler and send protocol specific report having size 11 bytes. I use Wireshark to sniff usb and I see that I can only send 8 bytes. If I try even 9 byte there is no payload at all.
I changed wMaxPacketSize in endpoint descriptor. Then I changed size of 'pressure' report size from 8 to 11, but it also didn't help. I found out that low speed devices allow only 8bytes per packet. But here author of teensy tells that it operates on 12Mbit/s and therefore should support 64bytes.
Could anyone tell me where am I wrong? How to make it send more than 8 bytes at once?
I'm hanging out with that about 2 days with no success.
-- Update --
Why do you want to change the amount of bytes?
As I said I need to make an emulator of 3M touchscreen. So, it has it's own protocol you can see the spec here. Page 18 describes touch report sent to host when touch occurs. It's size is 11 bytes.
I changed void usb_touchscreen_update_callback(void) that is defined in usb_touch.c to make it to send necessary structure (ref to spec page 18).
Here I found out that I can't send more then 8 bytes. If I try to send the payload voids at all.
What descriptor are you using?
I use endpoint descriptor that regards to an interface with bInterfaceClass field assigned 3 (HID). In this endpoint descriptor that is originally used for Touchscreen emulator by teensy lib I set wMaxPacketSize to 11. Originally it was set to 8. These interface, HID interface, endpoint descriptors are defined if MULTITOUCH_INTERFACE macro available.
#ifdef MULTITOUCH_INTERFACE
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
MULTITOUCH_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
LSB(sizeof(multitouch_report_desc)), // wDescriptorLength
MSB(sizeof(multitouch_report_desc)),
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
MULTITOUCH_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
MULTITOUCH_SIZE, 0, // wMaxPacketSize
1, // bInterval
#endif // KEYMEDIA_INTERFACE
There is MULTITOUCH_SIZE macro is set by header to 11.
Farther investigation cause I found out that joystick has 12 bytes packet length and it really sends them while having the same interface, HID interface and endpoint descriptors as touchscreen has. So looks like they only different in HID report descriptors
This HID report descriptor regards to touchscreen
static uint8_t multitouch_report_desc[] = {
0x05, 0x0D, // Usage Page (Digitizer)
0x09, 0x04, // Usage (Touch Screen)
0xa1, 0x01, // Collection (Application)
0x09, 0x22, // Usage (Finger)
0xA1, 0x02, // Collection (Logical)
0x09, 0x42, // Usage (Tip Switch)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (variable,absolute)
0x09, 0x51, // Usage (Contact Identifier)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x07, // Report Size (7)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (variable,absolute)
0x09, 0x30, // Usage (Pressure)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x0b, // Report Size (11)
// 0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (variable,absolute)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x26, 0xFF, 0x7F, // Logical Maximum (32767)
0x65, 0x00, // Unit (None) <-- probably needs real units?
0x75, 0x10, // Report Size (16)
0x95, 0x02, // Report Count (2)
0x81, 0x02, // Input (variable,absolute)
0xC0, // End Collection
0x05, 0x0D, // Usage Page (Digitizer)
0x27, 0xFF, 0xFF, 0, 0, // Logical Maximum (65535)
0x75, 0x10, // Report Size (16)
0x95, 0x01, // Report Count (1)
0x09, 0x56, // Usage (Scan Time)
0x81, 0x02, // Input (variable,absolute)
0x05, 0x0D, // Usage Page (Digitizers)
0x09, 0x55, // Usage (Contact Count Maximum)
0x25, MULTITOUCH_FINGERS, // Logical Maximum (10)
0x75, 0x0b, // Report Size (11)
// 0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (variable,absolute)
0xC0 // End Collection
};
And this one to joystick
static uint8_t joystick_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x20, // Report Count (32)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (Button #1)
0x29, 0x20, // Usage Maximum (Button #32)
0x81, 0x02, // Input (variable,absolute)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x07, // Logical Maximum (7)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x65, 0x14, // Unit (20)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x39, // Usage (Hat switch)
0x81, 0x42, // Input (variable,absolute,null_state)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection ()
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x03, // Logical Maximum (1023)
0x75, 0x0A, // Report Size (10)
0x95, 0x04, // Report Count (4)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz)
0x81, 0x02, // Input (variable,absolute)
0xC0, // End Collection
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x03, // Logical Maximum (1023)
0x75, 0x0A, // Report Size (10)
0x95, 0x02, // Report Count (2)
0x09, 0x36, // Usage (Slider)
0x09, 0x36, // Usage (Slider)
0x81, 0x02, // Input (variable,absolute)
0xC0 // End Collection
};
Then I replaced the first one with the second one and after that I have complete 11 bytes sent via this endpoint. Then I changed first byte 0x01 (Generic Desktop) to 0x0d (Digitizer) and now I have my cursor on Linux moves. On Windows driver is failed to install unfortunately.
Also it was necessary to change touchscreen interface to 0 and endpoint to 1 due to original device has only one interface and one endpoint.
But anyway I still don't know the reason why first HID report descriptor prevents from sending more than 8 bytes. So I ended up on reading this article https://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/.
Also I need no to know everything about USB. I just need the level of understanding to make this emulator work properly.
-- Update --
I'm on Linux, so I use Wireshark. But the issue is that this 3M original device is not HID device, so it has no HID report descriptor. The device populate only one interface that marked as Vendor specific. The field bInterfaceClass has 0xff value.
On the picture below are original device's descriptors
And here descriptors of teensy
As you can see the only difference is in bInterfaceClass value that is for teensy 0x03 (also bInterval in endpoint descriptor is slightly different, but I suppose it's value doesn't matter for this issue).
If I try to get rid of HID report descriptor and make interface equal to 0xff the device doesn't work. Also if I try to get rid of unnecessary extra interfaces (that comes from teensy) having 1, 2, 3 indexes it doesn't work.
Following picture shows the result where there is only one interface and endpoint as original device provides see the first pic (dark one). And the field bInterfaceClass is set to 0xff Vendor specific. The communication to host looks normally except there is no response to USB_INTERRUPT in from endpoint. While the original device has the response.
Is there any subtle things regarding to non HID devices? How to make the device to be non HID device?
Do you notice that nobody answers your question here? Not even a comment! There are very very few USB experts in the world. I worked over one year with USB at the lowest level (bits and bytes) and I learned a lot. And for the difficult parts I had to buy an expensive USB analyzer from Beagle. It is a very hard work because you simply don't get help from nobody with your USB problems. And Paul Stoffregen (who knows) will not have time to help you with this. He is busy with his own stuff. He hardly answers questions in his forum.
1:
You are correct that Low speed devices allow a maximum of 8 bytes while Full speed allows 64 bytes.
2:
If I understand you correctly you use the touchscreen descriptor of Teensyduino to emulate a 3M touchscreen? This is wrong. If you want to emulate a 3M touchscreen you MUST use the exactly same descriptors as the real 3M touchscreen does. This is the only guarantee that your emulator will work the same on all operating systems using the same drivers as the real 3M touchscreen. If you have this touchscreen available use the software USBLyzer to extract the descriptors from the real 3M touchscreen.
3:
You can also use USBLyzer to verify your own descriptors. BUT there is a very big catch: Windows remembers USB devices in the registry. When you make changes in the descriptor you must always assign a new ProductID in your Teensy so Windows will detect it as a new device. Otherwise your changes on the descriptors will have no effect or will not work.
4:
Your main problem seems to be the same problem which I had when I worked on this project: https://www.codeproject.com/Articles/1001891/A-USB-HID-Keyboard-Mouse-Touchscreen-emulator-with
The code in TeensyDuino (written by Paul Stoffregen) is hard to understand. He optimized the code for only one purpose: To use as less as possible RAM and store all the descriptor stuff in the non volatile memory of the Teensy. For that reason all his definitions are hard coded. It is a very hard work to understand his code and even harder to modify it without breaking it.
5:
I set wMaxPacketSize to 11.
This is wrong. Use the original 3M descriptor! Apart from that this does not solve your problem. This value is only an information for the driver. It does not affect the amount of bytes sent in Teensy code.
6.
Also I added my USB isr handler...
I don't know why should do this? This is not necessary.
7.
Here I found out that I can't send more then 8 bytes. If I try to send the payload voids at all.
Where do you see that? You are missing information here. Where do you see that the payload is void? As you already discovered there IS no limitation because the joystick sends more than 8 bytes.
Did you analyze the packets with USBLyzer? Without this information it is difficult to answer. Did you adapt the values in the section
// **************************************************************
// USB Descriptor Sizes
// **************************************************************
Use USBlyzer to capture the packets sent from the real 3M touch screen and compare them with the packets of your Teensy. Obviously ALL the descriptors must be identical before doing this.
I'm hanging out with that about 2 days with no success.
You will need far more time to learn USB. You need a lot programming experience, reverse engineering experience and a lot of patience and intelligence.
The most important thing is that you first study the code of Paul Stoffregen until you understood it 100%. Otherwise changing a value here and there without understanding what you are doing, you will just waste your time.