共用方式為


如何在UWP app (傳送USB大量傳輸要求)

在本主題中,您將瞭解USB大量傳輸,以及如何從與USB裝置通訊的UWP app起始傳輸要求。

USB 全速、高速和超級裝置可以支援大量端點。 這些端點用於傳輸大量數據,例如將數據傳輸至 USB 快閃磁碟驅動器或從 USB 快閃磁碟驅動器傳輸。 大量傳輸很可靠,因為它們允許錯誤偵測,而且涉及有限的重試次數,以確保主機或裝置會接收數據。 大量傳輸用於非時間關鍵的數據。 只有在總線上有未使用的頻寬可用時,才會傳輸數據。 因此,當總線忙碌於其他傳輸時,大量數據可能會無限期地等候。

大量端點是單向的,而且在一次傳輸中,數據可以透過 IN 或 OUT 方向傳輸。 若要支援讀取和寫入大量數據,裝置必須支援大量 IN 和大量 OUT 端點。 大量 IN 端點可用來將資料從裝置讀取到主機,並使用大量 OUT 端點將數據從主機傳送至裝置。

若要起始大量傳輸要求,您的應用程式必須具有代表端點之 管道 的參考。 管道是裝置驅動程式在設定裝置時所開啟的通道。 針對應用程式,管道是端點的邏輯表示法。 若要從端點讀取數據,應用程式會從相關聯的大量 IN 管道取得數據。 若要將數據寫入端點,應用程式會將數據傳送至大量 OUT 管道。 如需大量讀取和寫入管道,請使用 UsbBulkInPipeUsbBulkOutPipe 類別。

您的應用程式也可以藉由設定特定原則旗標來修改管道的行為。 例如,針對讀取要求,您可以設定旗標,以自動清除管道上的停止條件。 如需這些旗標的相關信息,請參閱 UsbReadOptionsUsbWriteOptions

開始之前

步驟 1:取得大量管道物件

若要起始傳輸要求,您必須 (UsbBulkOutPipeUsbBulkInPipe 取得大量管道對象的參考。 您可以列舉所有介面的所有設定,以取得管道。 不過,對於數據傳輸,您只能使用使用中設定的管道。 如果關聯端點不在作用中設定中,則管道物件為 Null。

如果您想要... 使用這個屬性值
將數據傳送至大量管道,取得 UsbBulkOutPipe 的參考。 如果您的裝置設定公開一個 USB 介面,UsbDevice.DefaultInterface.BulkOutPipes[n]

UsbDevice.Configuration.UsbInterfaces[m]。BulkOutPipes[n] 用於 列舉裝置所支援之多個介面中的大量 OUT 管道。

UsbInterface.InterfaceSettings[m]。BulkOutEndpoints[n]。用於列舉 介面中設定所定義之大量 OUT 管道的管道。

UsbEndpointDescriptor.AsBulkOutEndpointDescriptor.Pipe ,可從大量 OUT 端點的端點描述元取得管道物件。
從大量管道接收數據,您可以取得 UsbBulkInPipe 物件。 如果您的裝置設定公開一個USB介面,則UsbDevice.DefaultInterface.BulkInPipes[n]。

UsbDevice.Configuration.UsbInterfaces[m]。BulkInPipes[n] 用於 列舉裝置所支援之多個介面中的大量 IN 管道。

UsbInterface.InterfaceSettings[m]。BulkInEndpoints[n]。用於 列舉介面中設定所定義之大量 IN 管道的管道。

UsbEndpointDescriptor.AsBulkInEndpointDescriptor.Pipe ,可從大量 IN 端點的端點描述項取得管道物件。

注意

應該位於使用中的設定中,或需要 Null 檢查。

步驟 2:設定大量管道 (選擇性)

您可以在擷取的大量管道上設定特定旗標,以修改讀取或寫入作業的行為。

若要從裝置讀取,請將 UsbBulkInPipe.ReadOptions 屬性設定為 UsbReadOptions中定義的其中一個值。 在寫入的情況下,請將 UsbBulkOutPipe.WriteOptions 屬性設定為 UsbWriteOptions 中定義的其中一個值。

如果您想要... 設定此旗標
自動清除端點上的任何錯誤狀況,而不停止數據流 AutoClearStall

如需詳細資訊,請參閱 清除停止狀況

此旗標同時適用於讀取和寫入傳輸。
以最大效率傳送多個讀取要求。 略過錯誤檢查來提升效能。 OverrideAutomaticBufferManagement

數據要求可以分割成一或多個傳輸,其中每個傳輸都包含稱為傳輸大小上限的特定位元元組數目。 針對多個傳輸,佇列兩個傳輸可能會因為驅動程式所執行的錯誤檢查而延遲。 此旗標會略過該錯誤檢查。 若要取得傳輸大小上限,請使用 UsbBulkInPipe.MaxTransferSizeBytes 屬性。 如果您的要求大小是UsbBulkInPipe.MaxTransferSizeBytes,您必須設定此旗標。

重要: 如果您設定此旗標,則必須要求管道封包大小上限的倍數中的數據。 該資訊會儲存在端點描述元中。 大小取決於裝置的總線速度。 針對完整速度、高速和超級速度;封包大小上限分別為 64、512 和 1024 個字節。 若要取得該值,請使用 UsbBulkInPipe.EndpointDescriptor.MaxPacketSize 屬性。

此旗標僅適用於讀取傳輸。
以零長度封包終止寫入要求 ShortPacketTerminate

傳送零長度封包,以指出 OUT 傳輸的結尾。

此旗標僅適用於寫入傳輸。
停用讀取簡短封包 (端點支援的封包大小上限) IgnoreShortPacket

根據預設,如果裝置傳送的位元組小於封包大小上限,應用程式就會接收這些位元組。 如果您不想接收簡短封包,請設定此旗標。

此旗標僅適用於讀取傳輸。

步驟 3:設定數據流

當裝置傳送大量數據時,數據會以大量管道上的輸入數據流的形式接收。 以下是取得輸入資料流的步驟:

  1. 取得 UsbBulkInPipe.InputStream 屬性,以取得輸入數據流的參考。
  2. DataReader 建構函式中指定輸入數據流,以建立 DataReader 物件。

若要將數據寫入裝置,應用程式必須寫入大量管道上的輸出數據流。 以下是準備輸出資料流的步驟:

  1. 取得 UsbBulkOutPipe.OutputStream 屬性,以取得輸出數據流的參考。
  2. DataWriter 建構函式中指定輸出數據流,以建立 DataWriter 物件。
  3. 填入與輸出數據流相關聯的數據緩衝區。
  4. 根據數據類型,藉由呼叫 DataWriter 方法將數據傳輸至輸出數據流,例如 WriteBytes

步驟 4:啟動異步傳輸作業

大量傳輸是透過異步操作起始。

若要讀取大量數據,請呼叫 DataReader.LoadAsync 來啟動異步讀取作業。

若要寫入大量數據,請呼叫 DataWriter.StoreAsync 來啟動異步寫入作業。

步驟 5:取得讀取傳輸作業的結果

異步數據作業完成之後,您可以取得從工作物件讀取或寫入的位元組數目。 如需讀取作業,請呼叫 DataReader 方法,例如 ReadBytes,以從輸入數據流讀取數據。

清除停止狀況

有時候,應用程式可能會遇到數據傳輸失敗。 失敗的傳輸可能是因為端點上的停止狀況所造成。 只要端點停止,就無法將數據寫入或讀取。 若要繼續進行數據傳輸,應用程式必須清除相關聯管道上的停止條件。

您的應用程式可以設定管道,以在發生停止狀況時自動清除停止狀況。 若要這樣做,請將 UsbBulkInPipe.ReadOptions 屬性設定為 UsbReadOptions.AutoClearStallUsbBulkOutPipe.WriteOptions 屬性為 UsbWriteOptions.AutoClearStall。 透過該自動設定,應用程式不會經歷失敗的傳輸,而且數據傳輸體驗是順暢的。

若要手動清除停止條件,請針對大量 IN 管道呼叫 UsbBulkInPipe.ClearStallAsync ;針對大量 OUT 管道呼叫 UsbBulkOutPipe.ClearStallAsync

注意

停止條件不表示空的端點。 如果端點中沒有數據,則傳輸會完成,但長度為零位元組。

針對讀取作業,您可能需要清除管道中的擱置數據,再啟動新的傳輸要求。 若要這樣做,請呼叫 UsbBulkInPipe.FlushBuffer 方法。

USB 大量傳輸程式代碼範例

此程式代碼範例示範如何寫入大量管道。 此範例會將數據傳送至預設介面上的第一個大量 OUT 管道。 它會設定管道,以在傳輸結束時傳送長度為零的封包。 當傳輸完成時,會顯示位元組數目。

    private async void BulkWrite()
    {
        String dataBuffer = "Hello World!";
        UInt32 bytesWritten = 0;

        UsbBulkOutPipe writePipe = usbDevice.DefaultInterface.BulkOutPipes[0];
        writePipe.WriteOptions |= UsbWriteOptions.ShortPacketTerminate;

        var stream = writePipe.OutputStream;

        DataWriter writer = new DataWriter(stream);

        writer.WriteString(dataBuffer);

        try
        {
            bytesWritten = await writer.StoreAsync();
        }
        catch (Exception exception)
        {
            ShowStatus(exception.Message.ToString());
        }
        finally
        {
            ShowStatus("Data written: " + bytesWritten + " bytes.");
        }
    }

此程式代碼範例示範如何從大量管道讀取。 此範例會從預設介面上的第一個大量 IN 管道擷取數據。 它會設定管道以達到最大效率,並以封包大小上限區塊接收數據。 當傳輸完成時,會顯示位元組數目。

    private async void BulkRead()
    {
        UInt32 bytesRead = 0;

        UsbBulkInPipe readPipe = usbDevice.DefaultInterface.BulkInPipes[0];

        // Warning: Setting IgnoreShortPacket causes LoadAsync to block until you receive a number of packets >= readPipe.EndpointDescriptor.MaxPacketSize.
        // Remove the following line if you want to see messages that are less than the max transfer size, for example if you are communicating with a USBTMC device. 
        readPipe.ReadOptions |= UsbReadOptions.IgnoreShortPacket;

        var stream = readPipe.InputStream;
        DataReader reader = new DataReader(stream);

        try
        {
            bytesRead = await reader.LoadAsync(readPipe.EndpointDescriptor.MaxPacketSize);
        }
        catch (Exception exception)
        {
            ShowStatus(exception.Message.ToString());
        }
        finally
        {
            ShowStatus("Number of bytes: " + bytesRead);

            IBuffer buffer = reader.ReadBuffer(bytesRead);

            using (var dataReader = Windows.Storage.Streams.DataReader.FromBuffer(buffer))
            {
                dataReader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
                ShowData(dataReader.ReadString(buffer.Length));
            }
        }
    }