如何在UWP app (傳送USB大量傳輸要求)
在本主題中,您將瞭解USB大量傳輸,以及如何從與USB裝置通訊的UWP app起始傳輸要求。
USB 全速、高速和超級裝置可以支援大量端點。 這些端點用於傳輸大量數據,例如將數據傳輸至 USB 快閃磁碟驅動器或從 USB 快閃磁碟驅動器傳輸。 大量傳輸很可靠,因為它們允許錯誤偵測,而且涉及有限的重試次數,以確保主機或裝置會接收數據。 大量傳輸用於非時間關鍵的數據。 只有在總線上有未使用的頻寬可用時,才會傳輸數據。 因此,當總線忙碌於其他傳輸時,大量數據可能會無限期地等候。
大量端點是單向的,而且在一次傳輸中,數據可以透過 IN 或 OUT 方向傳輸。 若要支援讀取和寫入大量數據,裝置必須支援大量 IN 和大量 OUT 端點。 大量 IN 端點可用來將資料從裝置讀取到主機,並使用大量 OUT 端點將數據從主機傳送至裝置。
若要起始大量傳輸要求,您的應用程式必須具有代表端點之 管道 的參考。 管道是裝置驅動程式在設定裝置時所開啟的通道。 針對應用程式,管道是端點的邏輯表示法。 若要從端點讀取數據,應用程式會從相關聯的大量 IN 管道取得數據。 若要將數據寫入端點,應用程式會將數據傳送至大量 OUT 管道。 如需大量讀取和寫入管道,請使用 UsbBulkInPipe 和 UsbBulkOutPipe 類別。
您的應用程式也可以藉由設定特定原則旗標來修改管道的行為。 例如,針對讀取要求,您可以設定旗標,以自動清除管道上的停止條件。 如需這些旗標的相關信息,請參閱 UsbReadOptions 和 UsbWriteOptions。
開始之前
- 您必須開啟裝置並取得 UsbDevice 物件。 請參閱 如何連線到 UWP app () 的 USB 裝置 。
- 您可以在 CustomUsbDeviceAccess 範例Scenario4_BulkPipes檔案中看到本主題中顯示的完整程序代碼。
步驟 1:取得大量管道物件
若要起始傳輸要求,您必須 (UsbBulkOutPipe 或 UsbBulkInPipe 取得大量管道對象的參考。 您可以列舉所有介面的所有設定,以取得管道。 不過,對於數據傳輸,您只能使用使用中設定的管道。 如果關聯端點不在作用中設定中,則管道物件為 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:設定數據流
當裝置傳送大量數據時,數據會以大量管道上的輸入數據流的形式接收。 以下是取得輸入資料流的步驟:
- 取得 UsbBulkInPipe.InputStream 屬性,以取得輸入數據流的參考。
- 在 DataReader 建構函式中指定輸入數據流,以建立 DataReader 物件。
若要將數據寫入裝置,應用程式必須寫入大量管道上的輸出數據流。 以下是準備輸出資料流的步驟:
- 取得 UsbBulkOutPipe.OutputStream 屬性,以取得輸出數據流的參考。
- 在 DataWriter 建構函式中指定輸出數據流,以建立 DataWriter 物件。
- 填入與輸出數據流相關聯的數據緩衝區。
- 根據數據類型,藉由呼叫 DataWriter 方法將數據傳輸至輸出數據流,例如 WriteBytes。
步驟 4:啟動異步傳輸作業
大量傳輸是透過異步操作起始。
若要讀取大量數據,請呼叫 DataReader.LoadAsync 來啟動異步讀取作業。
若要寫入大量數據,請呼叫 DataWriter.StoreAsync 來啟動異步寫入作業。
步驟 5:取得讀取傳輸作業的結果
異步數據作業完成之後,您可以取得從工作物件讀取或寫入的位元組數目。 如需讀取作業,請呼叫 DataReader 方法,例如 ReadBytes,以從輸入數據流讀取數據。
清除停止狀況
有時候,應用程式可能會遇到數據傳輸失敗。 失敗的傳輸可能是因為端點上的停止狀況所造成。 只要端點停止,就無法將數據寫入或讀取。 若要繼續進行數據傳輸,應用程式必須清除相關聯管道上的停止條件。
您的應用程式可以設定管道,以在發生停止狀況時自動清除停止狀況。 若要這樣做,請將 UsbBulkInPipe.ReadOptions 屬性設定為 UsbReadOptions.AutoClearStall 或 UsbBulkOutPipe.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));
}
}
}