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?