如何发送 USB 中断传输请求(Windows 应用商店应用)

USB 设备可以支持中断终结点,从而能定期发送或接收数据。为实现这一点,主机定期轮询设备,每次主机轮询设备时,均会传输数据。中断传输大多是用来从设备获取中断数据。 本主题说明 Windows 应用商店应用如何从设备获取持续的中断数据。

中断终结点信息

对于中断终结点,描述符体现了这些属性。这些值仅供参考,不影响你管理缓冲区传输缓冲区的方式。

  • 数据传输的频率是多少?

    通过获取终结点描述符的 Interval 值可了解该信息(请参阅 UsbInterruptOutEndpointDescriptor.IntervalUsbInterruptInEndpointDescriptor.Interval)。该值表示总线上每个帧中向设备发送或从设备接收数据的频率。

    注意  Interval 属性不是 bInterval 值(在 USB 规范中定义)。

    该值表示向设备传输或从设备传输数据的频率。例如,对于高速设备,如果 Interval 是 125 微妙,则每 125 微秒传输一次数据。如果 Interval 是 1000 微秒,则每毫秒传输一次数据。

  • 在每个服务间隔中,可以达到的数据传输量是多少?

    通过获取终结点描述符支持的最大包大小可了解能达到的传输字节数(请参见 UsbInterruptOutEndpointDescriptor.MaxPacketSize 或 UsbInterruptInEndpointDescriptor.MaxPacketSize)。最大包大小取决于设备的速度。对于高速设备,最高为 8 字节。对于全速设备,最高为 64 字节。对于高速、高宽带设备,应用能够以超出最大包大小的水平发送或接收数据,最高可达 3072 字节/微帧。

    注意  SuperSpeed 设备上的中断终结点的传输速度甚至可以达到更高。该值由 USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR 的 wBytesPerInterval 表示。若要检索该描述符,可通过使用 UsbEndpointDescriptor.AsByte 属性获取描述符缓冲区,然后使用 DataReader 方法分析该缓冲区。

中断输出传输

USB 设备可以支持定期从主机接收数据的中断输出终结点。主机每次轮询设备时均会发送数据。Windows 应用商店应用可以发起中断输出传输请求,并且这类请求可指定要发送的数据。当设备确认收到主机的数据时,该请求即完成。Windows 应用商店应用可以向 UsbInterruptOutPipe 写入数据。

中断输入传输

反之,USB 设备可以支持中断输入终结点,从而通知主机有关设备已经生成硬件中断的信息。 通常,键盘和指针设备等 USB 人体学输入设备 (HID) 支持中断输出终结点。发生中断时,终结点会存储中断数据,但该数据不会立即到达主机。终结点必须等待主控制器对设备进行轮询。由于必须尽量缩短数据生成时间与数据到达主机时间之间的间隔,因此主机会定期轮询设备。Windows 应用商店应用可以获取 UsbInterruptInPipe 中接收到的数据。主机接收到设备发送的数据时,该请求即完成。

开始之前...

向中断输出终结点写入数据

应用发送中断输出传输的方式与批量输出传输相同,只不过前者的目标是中断输出管道,由 UsbInterruptOutPipe 表示。有关详细信息,请参阅如何发送 USB 批量传输请求(Windows 应用商店应用)

步骤 1:实现中断事件处理程序(中断输入)

当从设备接收的数据进入中断管道时,它会引发 DataReceived 事件。若要获取中断数据,应用必须实现一个事件处理程序。处理程序的 eventArgs 参数指向数据缓冲区。

此示例代码显示了事件处理程序的一个简单实现。处理程序维护所接收中断的计数。每次调用该处理程序时,它会进行增量计数。处理程序从 eventArgs 参数获取数据缓冲区,然后显示中断计数和接收到的字节长度。


private async void OnInterruptDataReceivedEvent(UsbInterruptInPipe sender, UsbInterruptInEventArgs eventArgs)
{
    numInterruptsReceived++;

    // The data from the interrupt
    IBuffer buffer = eventArgs.InterruptData;

    // Create a DispatchedHandler for the because we are interracting with the UI directly and the
    // thread that this function is running on may not be the UI thread; if a non-UI thread modifies
    // the UI, an exception is thrown

    await Dispatcher.RunAsync(
                       CoreDispatcherPriority.Normal,
                       new DispatchedHandler(() =>
    {
        ShowData(
        "Number of interrupt events received: " + numInterruptsReceived.ToString()
        + "\nReceived " + buffer.Length.ToString() + " bytes");
    }));
}


步骤 2:获取中断管道对象(中断输入)

若要为 DataReceived 事件注册事件处理程序,请通过使用以下任一属性获取 UsbInterruptInPipe 的引用。

注意  请避免通过枚举当前未选中的接口设备的中断终结点来获取管道对象。若要传输数据,管道必须与活动设置中的终结点相关联。

步骤 3: 注册事件处理程序以开始接收数据(中断输入)

接下来,你必须在引发 DataReceived 事件的 UsbInterruptInPipe 对象上注册事件处理程序。

此示例代码说明了注册事件处理程序的方法。在此示例中,类始终跟踪事件处理程序、注册的事件处理程序对应的管道,以及管道当前是否在接收数据。所有这些信息在注销事件处理程序时都会用到,如下一步骤所示。


private void RegisterForInterruptEvent(TypedEventHandler<UsbInterruptInPipe, UsbInterruptInEventArgs> eventHandler)
{
    // Search for the correct pipe that has the specified endpoint number
    interruptPipe = usbDevice.DefaultInterface.InterruptInPipes[0];

    // Save the interrupt handler so we can use it to unregister
    interruptEventHandler = eventHandler;

    interruptPipe.DataReceived += interruptEventHandler;

    registeredInterruptHandler = true;
}



void RegisterForInterruptEvent(TypedEventHandler<UsbInterruptInPipe, UsbInterruptInEventArgs> eventHandler)
    // Search for the correct pipe that has the specified endpoint number
    interruptInPipe = usbDevice.DefaultInterface.InterruptInPipes.GetAt(pipeIndex);
        
    // Save the token so we can unregister from the event later
    interruptEventHandler = interruptInPipe.DataReceived += eventHandler;

    registeredInterrupt = true;    

}

注册事件处理程序后,每次关联的中断管道中接收到数据时,都会调用该处理程序。

步骤 4: 注销事件处理程序以停止接收数据(中断输入)

完成数据接收后,应注销事件处理程序。

此示例说明了注销事件处理程序的方法。在此示例中,如果该应用具有以前注册过的事件处理程序,则方法将获取跟踪的事件处理程序,然后在中断管道上将其注销。


private void UnregisterInterruptEventHandler()
{
    if (registeredInterruptHandler)
    {
        interruptPipe.DataReceived -= interruptEventHandler;

        registeredInterruptHandler = false;
    }
}



void UnregisterFromInterruptEvent(void)
{
    if (registeredInterrupt)
    {
        interruptInPipe.DataReceived -= eventHandler;

        registeredInterrupt = false;
    }
}

事件处理程序被注销后,由于在发生中断事件时不会再调用该事件处理程序,因而应用便停止从中断管道接收数据。这并不意味着中断管道停止获取数据。

 

 

显示:
© 2014 Microsoft