Подключение к USB-устройству (приложение UWP)

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

В этой статье рассматриваются следующие вопросы:

  • Использование объекта DeviceWatcher для обнаружения устройств
  • Открытие устройства для обмена данными
  • Закрытие устройства после завершения работы с ним

Важные API

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

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

  • Это первая тема серии. Перед началом работы с этим руководством необходимо создать базовый проект Visual Studio, который можно расширить в этом руководстве. Дополнительные сведения см. в статье Начало работы с приложениями UWP .
  • Примеры кода основаны на примере CustomUsbDeviceAccess. Полный пример можно скачать на этой странице коллекции кода.
  • Usb-устройство, используемое в руководстве, — это устройство SuperMUTT.
  • Чтобы использовать пространство имен Windows.Devices.Usb для написания приложения Windows, взаимодействующего с USB-устройством, в качестве драйвера функции на устройстве должен быть загружен драйвер Winusb.sys. Winusb.sys предоставляется корпорацией Майкрософт и входит в состав Windows в папке \Windows\System32\drivers .

Блок-схема: поиск устройства

Чтобы подключиться к USB-устройству, необходимо сначала найти устройство на основе различных шаблонов обнаружения, а затем подключиться к нему:

  • Подключитесь к любому USB-устройству с помощью определенного GUID интерфейса устройства.
  • Подключитесь к USB-устройству с определенным идентификатором поставщика и идентификатором продукта, а также с определенным GUID интерфейса устройства.
  • Подключитесь к USB-устройству с определенным идентификатором поставщика и идентификатором продукта, не зная GUID интерфейса устройства.
  • Подключитесь к USB-устройству с известным классом устройства.

обнаружение usb-устройств.

Основные понятия

Что такое GUID интерфейса устройства?

Драйвер модели ядра во время инициализации регистрирует и предоставляет идентификатор GUID, называемый GUID интерфейса устройства. Как правило, приложение использует предоставленный GUID для поиска связанного драйвера и его устройства, а затем открывает дескриптор для устройства. Полученный дескриптор используется для последующих операций чтения и записи.

Однако в случае Winusb.sys вместо драйвера, предоставляющего GUID интерфейса устройства, его можно предоставить одним из двух способов:

  • В дескрипторов ОС MS устройства. Изготовитель устройства задает DeviceInterfaceGUID в качестве настраиваемого свойства в дескрипторе расширенных свойств на устройстве. Дополнительные сведения см. в документе "Дескрипторы расширенных свойств" в разделе Дескрипторы ОС Майкрософт.
  • Если вы установили Winusb.sys вручную с помощью пользовательского INF- файла, inf зарегистрировал GUID в INF. См. статью Установка WinUSB (Winusb.sys).

Если для устройства найден GUID интерфейса устройства, приложение UWP может найти все устройства, соответствующие идентификатору GUID интерфейса устройства.

Как отображается идентификация USB-устройства в Windows?

Каждое USB-устройство должно содержать две части информации: идентификатор поставщика и идентификатор продукта.

USB-IF назначает эти идентификаторы, и изготовитель устройства должен предоставить их на устройстве. Так как вы можете получить эту информацию?

  • Даже если на устройстве нет загруженного драйвера устройства, то есть Windows обнаруживает его как "Неизвестное устройство", вы по-прежнему можете просматривать идентификаторы в диспетчер устройств в значении свойства Hardware Id. Это значение представляет собой сочетание этих двух идентификаторов. Например, для устройства SuperMUTT идентификатор оборудования — "USB\VID_045E&PID_F001"; идентификатор поставщика — "0x045E", а идентификатор продукта — "0xF001".

  • Если для устройства есть INF-файл, получите ее из раздела Модели .

  • Вы можете проверить различные параметры реестра. Самый простой способ — увидеть

    <HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB\идентификатор оборудования>

    Дополнительные сведения см. в разделе Записи реестра USB-устройств.

  • Идентификатор оборудования используется манифестом приложения для идентификации устройства.

    <Device Id="vidpid:045e f001">

Приложение UWP может найти все устройства, соответствующие определенному поставщику и идентификаторам продукта. Вы можете сузить результаты поиска, указав GUID интерфейса устройства.

Что такое классы USB-устройств?

Большинство USB-устройств соответствуют спецификациям класса устройств, утвержденным USB-IF. Используя эти спецификации, устройства аналогичного характера могут демонстрировать свои функциональные возможности стандартным способом. Самым большим преимуществом этого подхода является то, что устройство может использовать предоставленный корпорацией Майкрософт встроенный драйвер класса или универсальный драйвер Winusb.sys.

Некоторые устройства могут не соответствовать спецификации USB-IF. Вместо этого они предоставляют функциональность , определяемую поставщиком . Для таких устройств поставщик должен предоставить драйвер устройства или Winusb.sys можно использовать.

Независимо от того, определено ли устройство поставщиком или соответствует классу устройства, оно должно описывать сведения, связанные с классом устройства:

  • Код класса: указывает класс устройства, которому принадлежит устройство.
  • Код подкласса: в классе устройства указывает подкласс устройства.
  • Код протокола: протокол, используемый устройством.

Например, устройство SuperMUTT является устройством, определяемым поставщиком, и эта информация обозначается кодом класса FF. Если на устройстве код класса отображается как FEh, код подкласса — 02h, а код протокола — 00h, можно сделать вывод, что устройство является совместимым с классом устройством моста IrDA. Приложение UWP может взаимодействовать с устройствами, принадлежащими к следующим классам устройств:

  • ActiveSync
  • CdcControl
  • DeviceFirmwareUpdate
  • Irda
  • Измерения
  • PalmSync
  • PersonalHealthcare
  • Физический
  • VendorSpecific

Приложение UWP может найти все устройства, соответствующие определенному набору кодов классов, подклассов и протоколов.

Получение строки расширенного синтаксиса запросов (AQS) для устройства

Создайте строку расширенного запроса (AQS), содержащую идентификационную информацию об устройстве, которое требуется обнаружить. Вы можете создать строку, указав идентификаторы поставщика или продукта, GUID интерфейса устройства или класс устройства.

  • Если вы хотите указать идентификатор поставщика или идентификатор продукта или GUID интерфейса устройства, вызовите любую перегрузку GetDeviceSelector.

    В примере устройства SuperMUTT GetDeviceSelector извлекает строку AQS, аналогичную этой строке:

    "System.Devices.InterfaceClassGuid:="{DEE824EF-729B-4A0E-9C14-B7117D33A817}" AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True AND System.DeviceInterface.WinUsb.UsbVendorId:=1118 AND System.DeviceInterface.WinUsb.UsbProductId:=61441"

    Примечание Обратите внимание, что GUID интерфейса устройства, который отображается в строке, не указан. Этот GUID является фактическим GUID интерфейса устройства, зарегистрированным Winusb.sys для приложений UWP.

  • Если вы знаете класс устройства устройства или его коды класса, подкласса и протокола, вызовите GetDeviceClassSelector , чтобы создать строку AQS.

    Создайте объект UsbDeviceClass , указав значения свойств ClassCode, SubclassCode и ProtocolCode . Кроме того, если вы знаете класс устройства устройства, можно вызвать конструктор, указав определенное свойство UsbDeviceClasses .

Поиск устройства — базовый способ

Это самый простой способ найти USB-устройство. Дополнительные сведения см. в статье Краткое руководство. Перечисление часто используемых устройств.

  1. Передайте полученную строку AQS в FindAllAsync. Вызов извлекает объект DeviceInformationCollection .
  2. Циклическое прохождение коллекции. Каждая итерация получает объект DeviceInformation .
  3. Получение значения свойства DeviceInformation.Id . Строковое значение — это путь к экземпляру устройства. Например, "\\\\?\\USB#VID_045E&PID_078F#6&1b8ff026&0&5#{dee824ef-729b-4a0e-9c14-b7117d33a817}".
  4. Вызовите Метод FromIdAsync , передав строку экземпляра устройства и получите объект UsbDevice . Затем можно использовать объект UsbDevice для выполнения других операций, таких как отправка передачи элементов управления. Когда приложение завершит работу с объектом UsbDevice , оно должно освободить его, вызвав close. Примечание Когда приложение UWP приостанавливается, устройство закрывается автоматически. Чтобы избежать использования устаревшего дескриптора для будущих операций, приложение должно освободить ссылку UsbDevice .
    private async void OpenDevice()
    {
        UInt32 vid = 0x045E;
        UInt32 pid = 0x0611;

        string aqs = UsbDevice.GetDeviceSelector(vid, pid);

        var myDevices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(aqs);

        try
        {
            usbDevice = await UsbDevice.FromIdAsync(myDevices[0].Id);
        }
        catch (Exception exception)
        {
            ShowStatus(exception.Message.ToString());
        }
        finally
        {
            ShowStatus("Opened device for communication.");
        }

    }

Поиск устройства с помощью DeviceWatcher

Кроме того, можно динамически перечислять устройства. Затем приложение может получать уведомления о добавлении или удалении устройств или изменении свойств устройства. Дополнительные сведения см. в статье Получение уведомлений о добавлении, удалении или изменении устройств.

Объект DeviceWatcher позволяет приложению динамически обнаруживать устройства по мере их добавления и удаления из системы.

  1. Создайте объект DeviceWatcher , чтобы определить, когда устройство добавляется в систему или удаляется из нее. Объект необходимо создать, вызвав CreateWatcher и указав строку AQS.

  2. Реализуйте и регистрируйте обработчики событий Added и Removed в объекте DeviceWatcher . Эти обработчики событий вызываются при добавлении или удалении устройств (с одинаковыми идентификационными данными) из системы.

  3. Запустите и остановите объект DeviceWatcher .

    Приложение должно запустить объект DeviceWatcher путем вызова метода Start , чтобы оно запустите обнаружение устройств по мере их добавления или удаления из системы. И наоборот, приложение должно остановить DeviceWatcher , вызвав Stop, когда больше не требуется обнаруживать устройства. В примере есть две кнопки, позволяющие пользователю запускать и останавливать DeviceWatcher.

В этом примере кода показано, как создать и запустить наблюдатель за устройствами для поиска экземпляров устройства SuperMUTT.

void CreateSuperMuttDeviceWatcher(void)
{
    UInt32 vid = 0x045E;
    UInt32 pid = 0x0611;

    string aqs = UsbDevice.GetDeviceSelector(vid, pid);

    var superMuttWatcher = DeviceInformation.CreateWatcher(aqs);

    superMuttWatcher.Added += new TypedEventHandler<DeviceWatcher, DeviceInformation>
                              (this.OnDeviceAdded);

    superMuttWatcher.Removed += new TypedEventHandler<DeviceWatcher, DeviceInformationUpdate>
                            (this.OnDeviceRemoved);

    superMuttWatcher.Start();
 }

Открытие устройства

Чтобы открыть устройство, приложение должно запустить асинхронную операцию, вызвав статический метод FromIdAsync и передав путь к экземпляру устройства (полученный из DeviceInformation.Id). Результатом этой операции является объект UsbDevice , который используется для дальнейшего взаимодействия с устройством, например для передачи данных.

После завершения использования объекта UsbDevice его необходимо освободить. При освобождении объекта все ожидающие передачи данных отменяются. Процедуры обратного вызова завершения для этих операций по-прежнему вызываются с ошибкой "Отменено" или операция завершена.

Приложения C++ должны освободить ссылку с помощью ключевое слово удаления. Приложения C#/VB должны вызывать метод UsbDevice.Dispose . Приложения JavaScript должны вызывать UsbDevice.Close.

FromIdAsync завершается сбоем, если устройство используется или его не удается найти.