我有一个发送报告描述符的全速 USB 设备,其相关端点描述符声明 abInterval
为 8,即 8 毫秒。
当设备的驱动程序是 HidUsb 时,从 USB Descriptor Dumper 获取以下报告摘录:
Interface Descriptor: // +several attributes
------------------------------
0x04 bDescriptorType
0x03 bInterfaceClass (Human Interface Device Class)
0x00 bInterfaceSubClass
0x00 bInterfaceProtocol
0x00 iInterface
HID Descriptor: // +bLength, bCountryCode
------------------------------
0x21 bDescriptorType
0x0110 bcdHID
0x01 bNumDescriptors
0x22 bDescriptorType (Report descriptor)
0x00D6 bDescriptorLength
Endpoint Descriptor: // + bLength, bEndpointAddress, wMaxPacketSize
------------------------------
0x05 bDescriptorType
0x03 bmAttributes (Transfer: Interrupt / Synch: None / Usage: Data)
0x08 bInterval (8 frames)
在将驱动程序切换到 WinUSB 以便能够使用它之后,如果我使用 libusb 反复查询 IN 中断传输,并使用此脚本计算 2 个 libusb 调用之间和 libusb 调用期间花费的实际时间:
for (int i = 0; i < n; i++) {
start = std::chrono::high_resolution_clock::now();
forTime = (double)((start - end).count()) / 1000000;
<libusb_interrupt_transfer on IN interrupt endpoint>
end = std::chrono::high_resolution_clock::now();
std::cout << "for " << forTime << std::endl;
transferTime = (double)((end - start).count()) / 1000000;
std::cout << "transfer " << transferTime << std::endl;
std::cout << "sum " << transferTime + forTime << std::endl << std::endl;
}
这是获得值的示例:
for 2.60266
transfer 5.41087
sum 8.04307 //~8
for 3.04287
transfer 5.41087
sum 8.01353 //~8
for 6.42174
transfer 9.65907
sum 16.0808 //~16
for 2.27422
transfer 5.13271
sum 7.87691 //~8
for 3.29928
transfer 4.68676
sum 7.98604 //~8
总和值始终保持非常接近 8 毫秒,除非在启动新的中断传输调用之前经过的时间太长(对于我的特定情况,阈值似乎在 6 到 6.5 之间),在这种情况下它等于 16。我有曾经看到一个“for”度量等于 18 毫秒,而总和恰好等于 24 毫秒。使用 URB 跟踪器(在我的例子中是 Microsoft 消息分析器),Complete URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
消息之间的时间差也是 8 毫秒的倍数 - 通常是 8 毫秒。简而言之,它们与“总和”度量相匹配。
因此,很明显“libusb 中断传输调用”的两次返回之间经过的时间是 8ms 的倍数,我假设这与 bInterval 值 8(FullSpeed -> *1ms -> 8ms)有关。
但现在我已经,我希望,清楚地说明我在说什么——在哪里强制执行?尽管进行了研究,但我找不到关于 bInterval 值如何影响事物的明确解释。
显然,这是由驱动程序强制执行的。
因此,是不是:
驱动程序禁止请求触发,直到 8 毫秒过去。听起来对我来说是最合理的选择,但从我的 URB Trace 来看,
Dispatch message
事件在请求返回前几毫秒就被引发了。这意味着离开主机的实时数据对我/消息分析器是隐藏的。驱动程序对我和分析器隐藏响应,直到自上次响应以来经过 8 毫秒。
如果它确实由驱动程序处理,那么在交换消息的日志中向我显示的内容有一个谎言。响应应该在请求之后立即出现,但事实并非如此。因此,请求在显示的时间之后发送,或者响应早于显示的时间。
尊重 bInterval 的执行如何工作?
我的最终目标是忽略 bInterval 值并以超过 8ms 的频率轮询设备(我有充分的理由相信它可以每 2ms 轮询一次,并且 8ms 的使用周期是不可接受的),但首先我想知道它当前的限制是如何工作的,如果我正在寻找的是可能的,所以我可以理解接下来要学习什么(例如编写自定义 WinUSB 驱动程序)