Teensy 3.2 传出数据包有效载荷限制 8 个字节

Posted

技术标签:

【中文标题】Teensy 3.2 传出数据包有效载荷限制 8 个字节【英文标题】:Teensy 3.2 outgoing packet payload limit 8 bytes 【发布时间】:2020-07-31 11:30:24 【问题描述】:

我想模拟 3M USB 触摸屏控制器。我找到了确切的协议并稍微更改了 teensy3 库中的源代码。我更改了 VendorID 和 ProductID。我还添加了我的 USB isr 处理程序并发送大小为 11 字节的协议特定报告。我使用 Wireshark 嗅探 USB,我发现我只能发送 8 个字节。如果我尝试 9 字节,则根本没有有效负载。

我在端点描述符中更改了wMaxPacketSize。然后我将“压力”报告的大小从 8 更改为 11,但这也无济于事。我发现低速设备每个数据包只允许 8 个字节。但是here teensy 的作者告诉它,它以 12Mbit/s 的速度运行,因此应该支持 64 字节。

谁能告诉我我哪里错了?如何让它一次发送超过 8 个字节?

我在这玩了大约 2 天,但没有成功。

-- 更新--

    为什么要更改字节数?

正如我所说,我需要制作一个 3M 触摸屏的模拟器。因此,它有自己的协议,您可以查看规范 here。第 18 页描述了触摸发生时发送给主机的触摸报告。它的大小是 11 个字节。

我更改了usb_touch.c 中定义的void usb_touchscreen_update_callback(void) 以使其发送必要的结构(参考spec 第18 页)。

在这里我发现我不能发送超过 8 个字节。如果我尝试发送有效载荷无效。

    您使用的是什么描述符?

我使用与 interface 相关的 端点描述符,其中 bInterfaceClass 字段分配了 3 (HID)。在这个最初由 teensy lib 用于触摸屏模拟器的端点描述符中,我将 wMaxPacketSize 设置为 11。最初它设置为 8。这些 interfaceHID 接口、endpoint 如果MULTITOUCH_INTERFACE 宏可用,则定义描述符。

#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

MULTITOUCH_SIZE宏被header设置为11。

进一步调查原因我发现操纵杆有 12 字节的数据包长度,它确实在具有相同的 interfaceHID 接口endpoint 的情况下发送它们em> 像触摸屏一样的描述符。所以看起来它们只是在 HID 报告描述符中有所不同

HID 报告描述符与触摸屏有关

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
;

这个是操纵杆

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
;

然后我用第二个替换了第一个,之后我通过这个端点发送了完整的 11 个字节。然后我将第一个字节 0x01(通用桌面)更改为 0x0d(数字化仪),现在我的光标在 Linux 移动上。不幸的是,Windows 驱动程序无法安装。

此外,由于原始设备只有一个 interface 和一个 ,因此需要将触摸屏 interface 更改为 0 并将 endpoint 更改为 1 >端点

但无论如何我仍然不知道为什么第一个 HID 报告描述符 阻止发送超过 8 个字节。所以我最终阅读了这篇文章https://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/。

我也不需要知道关于 USB 的一切。我只需要理解的水平就可以让这个模拟器正常工作。

-- 更新--

我在 Linux 上,所以我使用 Wireshark。但问题是这个3M原装设备不是HID设备,所以它没有HID报告描述符。该设备仅填充一个标记为供应商特定的接口。字段bInterfaceClass 具有0xff 值。

下图是原始设备的描述符

这里是teensy的描述

正如您所看到的,唯一的区别在于 bInterfaceClass 的值是青少年 0x03 (端点描述符中的 bInterval 也略有不同,但我认为它的值对于这个问题并不重要)。

如果我尝试摆脱 HID 报告描述符 并使接口等于 0xff,则设备将无法工作。此外,如果我尝试摆脱具有 1、2、3 索引的不必要的额外接口(来自 teensy),它也不起作用。

下图显示了只有一个 interfaceendpoint 作为原始设备提供的结果,请参见第一张图片(深色)。并且字段bInterfaceClass 设置为0xff 供应商特定。除了端点没有对USB_INTERRUPT in 的响应外,与主机的通信看起来很正常。而原设备有响应。

关于非 HID 设备有什么微妙之处吗?如何使设备成为非HID设备?

【问题讨论】:

已更新,感谢回复 【参考方案1】:

您是否注意到这里没有人回答您的问题?连评论都没有!世界上的 USB 专家非常少。我在最低级别(位和字节)上使用 USB 工作了一年多,我学到了很多东西。对于困难的部分,我不得不从 Beagle 购买昂贵的 USB 分析仪。这是一项非常艰苦的工作,因为您根本无法从任何人那里获得 USB 问题的帮助。 Paul Stoffregen(谁知道)将没有时间帮助您解决这个问题。他忙于自己的事情。他几乎不回答论坛上的问题。

1:

您是正确的,低速设备最多允许 8 个字节,而全速设备最多允许 64 个字节。

2:

如果我理解正确,您使用 Teensyduino 的触摸屏描述符来模拟 3M 触摸屏?这是错误的。如果您想模拟 3M 触摸屏,您必须使用与真正的 3M 触摸屏完全相同的描述符。这是唯一保证您的模拟器在使用与真正的 3M 触摸屏相同的驱动程序的所有操作系统上都能正常工作。如果您有此触摸屏,请使用软件 USBLyzer 从真正的 3M 触摸屏中提取描述符。

3:

您也可以使用 USBLyzer 来验证您自己的描述符。但是有一个很大的问题:Windows 会记住注册表中的 USB 设备。当您在描述符中进行更改时,您必须始终在您的 Teensy 中分配一个新的 ProductID,以便 Windows 将其检测为新设备。否则,您对描述符的更改将无效或不起作用。

4:

您的主要问题似乎与我在从事此项目时遇到的问题相同:https://www.codeproject.com/Articles/1001891/A-USB-HID-Keyboard-Mouse-Touchscreen-emulator-with

TeensyDuino(由 Paul Stoffregen 编写)中的代码很难理解。他仅出于一个目的优化了代码:使用尽可能少的 RAM 并将所有描述符内容存储在 Teensy 的非易失性存储器中。出于这个原因,他的所有定义都是硬编码的。理解他的代码是一项非常艰巨的工作,更难的是在不破坏代码的情况下对其进行修改。

5:

我将 wMaxPacketSize 设置为 11。

这是错误的。使用原始的 3M 描述符!除此之外,这并不能解决您的问题。这个值只是给司机的信息。它不会影响以 Teensy 代码发送的字节数。

6.

我还添加了我的 USB isr 处理程序...

我不知道为什么要这样做?这不是必需的。

7.

在这里我发现我不能发送超过 8 个字节。如果我尝试发送有效载荷无效。

你在哪里看到的?您在这里缺少信息。您在哪里看到有效载荷是无效的?正如您已经发现的那样,没有限制,因为操纵杆发送超过 8 个字节。

您是否使用 USBLyzer 分析数据包?没有这些信息很难回答。您是否调整了该部分中的值

// **************************************************************
//   USB Descriptor Sizes
// **************************************************************

使用 USBlyzer 捕获从真正的 3M 触摸屏发送的数据包,并将它们与您的 Teensy 的数据包进行比较。显然所有的描述符在这样做之前必须是相同的。

我在这玩了大约 2 天,但没有成功。

您将需要更多时间来学习 USB。您需要大量的编程经验、逆向工程经验以及大量的耐心和智慧。

最重要的是,你首先要研究 Paul Stoffregen 的代码,直到你 100% 理解它。否则在不了解你在做什么的情况下到处改变一个值,你只会浪费你的时间。

【讨论】:

更新问题 现在我拒绝效仿 3M 并选择了 Elo。只需复制每个描述符,它就开始工作,Linux 和 Windows 识别它并安装驱动程序(win),我有指针移动。它具有 HID 报告描述符和 8 字节端点数据包大小。不幸的是,我找不到有关正在使用的协议的文档,但是我查看了 Linux 内核驱动程序源并发现了数据包格式,这很简单……但是校准需要进一步调查……

以上是关于Teensy 3.2 传出数据包有效载荷限制 8 个字节的主要内容,如果未能解决你的问题,请参考以下文章

数据包有效载荷中的更多数据

如果我在 C# 中发送 0 有效载荷数据,udp 数据包的大小是多少?

使用 PcapDotNet,你如何提取最终的有效载荷?

什么是开销、有效负载和标头 [关闭]

从 BLE v4.2 到 4.0 的有效载荷大小的向后兼容性

http中的净荷 payload(有效载荷有效负载)是什么?