Как отправить запрос на массовую передачу USB (приложение UWP)

В этом разделе вы узнаете о массовой передаче по USB и о том, как инициировать запрос на передачу из приложения UWP, которое взаимодействует с USB-устройством.

Полноскоростные usb-устройства, высокоскоростные устройства и устройства SuperSpeed могут поддерживать массовые конечные точки. Эти конечные точки используются для передачи больших объемов данных, например передачи данных на USB-устройство флэш-памяти или с его помощью. Массовые передачи надежны, так как они позволяют обнаруживать ошибки и включают ограниченное количество повторных попыток, чтобы убедиться, что данные получены узлом или устройством. Массовая передача используется для данных, которые не являются критически важными по времени. Данные передаются только при наличии неиспользуемой пропускной способности на шине. Таким образом, когда автобус занят другими передачами, массовые данные могут ждать неограниченное время.

Массовые конечные точки являются однонаправленными, и при одной передаче данные могут передаваться в направлении IN или OUT. Для поддержки чтения и записи массовых данных устройство должно поддерживать конечные точки массовых операций IN и BULK OUT. Конечная точка bulk IN используется для чтения данных с устройства на узел, а конечная точка bulk OUT — для отправки данных с узла на устройство.

Чтобы инициировать запрос на массовую передачу, приложение должно иметь ссылку на канал , представляющий конечную точку. Канал — это канал связи, открытый драйвером устройства при настройке устройства. Для приложения канал является логическим представлением конечной точки. Чтобы считывать данные из конечной точки, приложение получает данные из связанного массового канала IN. Чтобы записать данные в конечную точку, приложение отправляет данные в канал bulk OUT. Для каналов массового чтения и записи используйте классы UsbBulkInPipe и UsbBulkOutPipe .

Приложение также может изменить поведение канала, установив определенные флаги политики. Например, для запроса на чтение можно установить флаг, который автоматически очищает условие приостановки в канале. Сведения об этих флагах см. в разделах UsbReadOptions и UsbWriteOptions.

Перед началом работы

Шаг 1. Получение объекта массового канала

Чтобы инициировать запрос на передачу, необходимо получить ссылку на объект массового канала (UsbBulkOutPipe или UsbBulkInPipe). Каналы можно получить путем перечисления всех параметров всех интерфейсов. Однако для передачи данных необходимо использовать только каналы активного параметра. Если объект канала имеет значение NULL, если связанная конечная точка не находится в активном параметре.

Цель... Использовать это значение свойства
Отправьте данные в массовый канал, получите ссылку на UsbBulkOutPipe. UsbDevice.DefaultInterface.BulkOutPipes[n] , если конфигурация устройства предоставляет один интерфейс USB.

UsbDevice.Configuration.UsbInterfaces[m]. BulkOutPipes[n] для перечисления массовых каналов OUT в нескольких интерфейсах, поддерживаемых устройством.

UsbInterface.InterfaceSettings[m]. BulkOutEndpoints[n]. Канал для перечисления массовых каналов OUT, определенных параметрами в интерфейсе.

UsbEndpointDescriptor.AsBulkOutEndpointDescriptor.Pipe для получения объекта канала из дескриптора конечной точки для конечной точки bulk OUT.
Получая данные из массового канала, можно получить объект UsbBulkInPipe . UsbDevice.DefaultInterface.BulkInPipes[n] , если конфигурация устройства предоставляет один ИНТЕРФЕЙС USB.

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, необходимо установить этот флаг.

Важно: Если этот флаг задан, необходимо запросить данные в кратных максимального размера пакета канала. Эти сведения хранятся в дескрипторе конечной точки. Размер зависит от скорости шины устройства. Для полной скорости, высокой скорости и SuperSpeed; максимальный размер пакета составляет 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.AutoClearStall или UsbBulkOutPipe.WriteOptions значение UsbWriteOptions.AutoClearStall. При этой автоматической настройке приложение не будет испытывать неудачные передачи, и передача данных является простой.

Чтобы очистить условие остановки вручную, вызовите UsbBulkInPipe.ClearStallAsync для массового канала IN; вызовите UsbBulkOutPipe.ClearStallAsync для канала bulk OUT.

Примечание

Условие остановки не указывает на пустую конечную точку. Если в конечной точке нет данных, передача завершается, но длина равна нулю байтов.

Для операций чтения может потребоваться очистить ожидающие данные в канале перед запуском нового запроса на передачу. Для этого вызовите метод 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.");
        }
    }

В этом примере кода показано, как считывать данные из массового канала. В этом примере извлекаются данные из первого конвейера массовой обработки в интерфейсе по умолчанию. Он настраивает для канала значение для максимальной эффективности и получает данные блоками максимального размера пакета. После завершения передачи отображается количество байтов.

    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));
            }
        }
    }