【问题标题】:WebUSB `USBTransferInResult`s seem to contain partial interrupt transfersWebUSB `USBTransferInResult`s 似乎包含部分中断传输
【发布时间】:2022-01-11 06:20:35
【问题描述】:

我在 Chrome 中使用 WebUSB API。我可以与设备配对,声明一个接口,并开始监听一个入站中断端点,每次按下按钮时传输三个字节,释放按钮时再传输三个字节(这是供应商特定的 MIDI 实现)。

USBTransferInResult.data.buffer 包含它应该包含的所有字节,除非它们没有按传输方式提供。字节一次传输一个字节,除非我同时生成一堆数据,在这种情况下,同一个USBTransferInResult 中可能有多达三个或四个字节。

注意:此端点的最大数据包大小为8。我尝试将其设置为 1256 之类的东西,但没有任何效果。

如果我连接所有的结果缓冲区,我会得到我期望的确切数据,但 API 肯定应该使每次传输(看似)原子。

这可能是由于供应商(Focusrite - 它是 Novation 产品)使用不符合标准的 MIDI 实现而做的一些时髦的事情的结果。我只是假设供应商更愿意将每个 MIDI 消息作为原子中断传输(而不是三个快速连续的单字节传输)传输,因为它会简化驱动程序并使其更加健壮。我看不出分解这些消息的好处。

注意:如果我启用experimental-usb-backend,我的USB设备将停止出现在对话框中(当requestDevice被调用时)。

这是我正在测试它的代码:

let DEVICE = undefined;

const connect = async function() {

    /* Initialize the device, assign it to the global variable,
    claim Interface 1, then invoke `listen`. */

    const filters = [{vendorId: 0x1235, productId: 0x0018}];

    DEVICE = await navigator.usb.requestDevice({filters});

    await DEVICE.open();
    await DEVICE.selectConfiguration(1);
    await DEVICE.claimInterface(1);

    listen();
};

const listen = async function() {

    /* Recursively, listen for each interrupt transfer from
    Endpoint 4, asking for upto 8 bytes each time, and then
    logging each transfer (as a regular array of numbers). */

    const result = await DEVICE.transferIn(4, 8);
    const data = new Uint8Array(result.data.buffer);

    console.log(Array.from(data));
    listen();
};

// Note: The are a few lines of UI code here that provide a
// button for invoking the `connect` function above, and
// another button that invokes the `close` method of
// the USB device.

鉴于此问题在没有 USB 设备的情况下无法重现,我不想将其报告为错误,除非我确定它是一个错误。我希望这里有人可以帮助我。

我是否误解了 WebUSB API 的工作方式?

假设供应商可能打算将 MIDI 消息分解为单个字节是否合理?

【问题讨论】:

    标签: usb webusb


    【解决方案1】:

    仔细想想,这种工作方式可能是有意的。

    USB MIDI 规范非常复杂,因为它试图适应复杂的 MIDI 设置,而这些设置本身就可以构成整个网络。我正在破解的设备(Novation Twitch DJ 控制器)没有 MIDI 连接,因此 Novation 工程师将每条 MIDI 消息作为 USB 中断传输传递会容易得多。

    至于它在 MIDI 字节准备好后立即流式传输的方式,我假设这简化了硬件,并且旨在像字节码一样被解释。每条 MIDI 消息都以一个状态字节开始,该状态字节指示后面的数据字节数(类似于操作码,后跟一些立即数)。

    注意:状态字节也有一个前导 1,而数据字节有一个前导 0,因此它们很容易区分(并且 SysEx 消息使用特定的开始和结束字节)。

    最后,使用状态字节来指示何时实例化新消息以及它应该是什么类型非常简单。然后我实现了一组 MIDI 消息类(NoteOnControlSysEx 等),每个类都知道它们何时具有正确的字节数(以简化每个单独消息的逻辑)。

    【讨论】:

    • 这正是我会发布的答案。 MIDI 是一种串行协议,可能发生的情况是 USB 芯片有一个小缓冲区,用于通过 MIDI 连接接收到的数据。每当从主机收到 IN 传输请求时,它都会响应缓冲区中的任何内容(最多 8 字节数据包大小),因此如果您轮询设备的速度比 MIDI 数据传输速率快得多,您将获得一个字节一次,因为这就是缓冲区中的所有内容。这也是大多数通用 USB 到 RS-232 串行转换器芯片的工作原理。
    • 我明白了。那讲得通。我隐约怀疑有类似的事情,但是让熟悉这些设备如何操作的人来解释它是有用的。谢谢。
    猜你喜欢
    • 2016-07-06
    • 1970-01-01
    • 2014-10-06
    • 2016-05-27
    • 2016-06-05
    • 1970-01-01
    • 1970-01-01
    • 2023-01-17
    • 2011-09-14
    相关资源
    最近更新 更多