Создайте устройство, чтобы в полной мере воспользоваться преимуществами API WebUSB.
В этой статье объясняется, как создать устройство, чтобы в полной мере использовать преимущества WebUSB API . Краткое введение в сам API см. в разделе Доступ к USB-устройствам в Интернете .
Фон
Универсальная последовательная шина (USB) стала наиболее распространенным физическим интерфейсом для подключения периферийных устройств к настольным и мобильным вычислительным устройствам. Помимо определения электрических характеристик шины и общей модели связи с устройством, спецификации USB включают набор спецификаций классов устройств. Это общие модели для определенных классов устройств, таких как устройства хранения, аудио, видео, сети и т. д., которые могут реализовать производители устройств. Преимущество этих спецификаций классов устройств заключается в том, что поставщик операционной системы может реализовать один драйвер на основе спецификации класса («драйвер класса»), и любое устройство, реализующее этот класс, будет поддерживаться. Это было большим шагом вперед по сравнению с тем, что каждому производителю приходилось писать свои собственные драйверы устройств.
Однако некоторые устройства не вписываются ни в один из этих стандартизированных классов устройств. Вместо этого производитель может пометить свое устройство как реализующее класс, специфичный для поставщика. В этом случае операционная система выбирает, какой драйвер устройства загрузить, на основе информации, предоставленной в пакете драйверов поставщика, обычно это набор идентификаторов поставщика и продукта, которые, как известно, реализуют определенный протокол, зависящий от поставщика.
Еще одна особенность USB заключается в том, что устройства могут предоставлять несколько интерфейсов хосту, к которому они подключены. Каждый интерфейс может реализовывать либо стандартизированный класс, либо зависеть от поставщика. Когда операционная система выбирает правильные драйверы для управления устройством, каждый интерфейс может быть востребован отдельным драйвером. Например, веб-камера USB обычно предоставляет два интерфейса: один реализует класс видео USB (для камеры), а другой — класс аудио USB (для микрофона). Операционная система не загружает ни одного «драйвера веб-камеры», а вместо этого загружает независимые драйверы видео и аудио классов, которые отвечают за отдельные функции устройства. Такой состав классов интерфейса обеспечивает большую гибкость.
Основы API
Многие стандартные классы USB имеют соответствующие веб-API. Например, страница может захватывать видео с устройства класса видео с помощью getUserMedia()
или получать события ввода от устройства класса пользовательского интерфейса (HID), прослушивая KeyboardEvents или PointerEvents или используя Gamepad или WebHID API. Точно так же, как не все устройства реализуют стандартизированное определение класса, не все устройства реализуют функции, соответствующие существующим API-интерфейсам веб-платформы. В этом случае API WebUSB может восполнить этот пробел, предоставив сайтам возможность требовать интерфейс конкретного поставщика и реализовывать его поддержку непосредственно на своей странице.
Конкретные требования к устройству, доступному через WebUSB, немного различаются от платформы к платформе из-за различий в том, как операционные системы управляют USB-устройствами, но основное требование заключается в том, что на устройстве еще не должно быть драйвера, претендующего на интерфейс, которым страница хочет управлять. Это может быть либо универсальный драйвер класса, предоставленный поставщиком ОС, либо драйвер устройства, предоставленный поставщиком. Поскольку USB-устройства могут предоставлять несколько интерфейсов, каждый из которых может иметь свой собственный драйвер, можно создать устройство, для которого некоторые интерфейсы запрашиваются драйвером, а другие остаются доступными для браузера.
Например, высокопроизводительная USB-клавиатура может предоставлять интерфейс класса HID, который будет востребован подсистемой ввода операционной системы, и интерфейс, зависящий от поставщика, который остается доступным для WebUSB для использования инструментом настройки. Этот инструмент можно разместить на веб-сайте производителя, позволяя пользователю изменять аспекты поведения устройства, такие как макроклавиши и световые эффекты, без установки какого-либо программного обеспечения для конкретной платформы. Дескриптор конфигурации такого устройства будет выглядеть примерно так:
Ценить | Поле | Описание |
---|---|---|
Дескриптор конфигурации | ||
0x09 | bДлина | Размер этого дескриптора |
0x02 | бдескриптортипе | Дескриптор конфигурации |
0x0039 | wTotalLength | Общая длина этой серии дескрипторов |
0x02 | bNumInterfaces | Количество интерфейсов |
0x01 | бConfigurationValue | Конфигурация 1 |
0x00 | iКонфигурация | Имя конфигурации (нет) |
0b1010000 | бмАтрибуты | Устройство с автономным питанием и удаленным пробуждением |
0x32 | бМаксПауэр | Максимальная мощность выражается с шагом 2 мА. |
Дескриптор интерфейса | ||
0x09 | bДлина | Размер этого дескриптора |
0x04 | бдескриптортипе | Дескриптор интерфейса |
0x00 | бИнтерфейсНомер | Интерфейс 0 |
0x00 | bАльтернативные настройки | Альтернативная настройка 0 (по умолчанию) |
0x01 | бнумендпойнтс | 1 конечная точка |
0x03 | бИнтерфейсКласс | класс интерфейса HID |
0x01 | bInterfaceSubClass | Подкласс загрузочного интерфейса |
0x01 | бПротокол интерфейса | Клавиатура |
0x00 | iИнтерфейс | Имя интерфейса (нет) |
HID-дескриптор | ||
0x09 | bДлина | Размер этого дескриптора |
0x21 | бдескриптортипе | HID-дескриптор |
0x0101 | bcdHID | СПРЯТАННАЯ версия 1.1 |
0x00 | бКод страны | Целевая страна оборудования |
0x01 | бнумдескрипторы | Количество дескрипторов классов HID, которым необходимо следовать. |
0x22 | бдескриптортипе | Тип дескриптора отчета |
0x003F | вдескрипторленгс | Общая длина дескриптора отчета |
Дескриптор конечной точки | ||
0x07 | bДлина | Размер этого дескриптора |
0x05 | бдескриптортипе | Дескриптор конечной точки |
0b10000001 | бEndpointAddress | Конечная точка 1 (ИН) |
0b00000011 | бмАтрибуты | Прерывать |
0x0008 | wMaxPacketSize | 8-байтовые пакеты |
0x0A | bИнтервал | интервал 10 мс |
Дескриптор интерфейса | ||
0x09 | bДлина | Размер этого дескриптора |
0x04 | бдескриптортипе | Дескриптор интерфейса |
0x01 | бИнтерфейсНомер | Интерфейс 1 |
0x00 | bАльтернативные настройки | Альтернативная настройка 0 (по умолчанию) |
0x02 | бнумендпойнтс | 2 конечные точки |
0xFF | бИнтерфейсКласс | Класс интерфейса, зависящий от поставщика |
0x00 | bInterfaceSubClass | |
0x00 | бПротокол интерфейса | |
0x00 | iИнтерфейс | Имя интерфейса (нет) |
Дескриптор конечной точки | ||
0x07 | bДлина | Размер этого дескриптора |
0x05 | бдескриптортипе | Дескриптор конечной точки |
0b10000010 | бEndpointAddress | Конечная точка 1 (ИН) |
0b00000010 | бмАтрибуты | Масса |
0x0040 | wMaxPacketSize | пакеты по 64 байта |
0x00 | bИнтервал | Н/Д для массовых конечных точек |
Дескриптор конечной точки | ||
0x07 | bДлина | Размер этого дескриптора |
0x05 | бдескриптортипе | Дескриптор конечной точки |
0b00000011 | бEndpointAddress | Конечная точка 3 (ВЫХОД) |
0b00000010 | бмАтрибуты | Масса |
0x0040 | wMaxPacketSize | пакеты по 64 байта |
0x00 | bИнтервал | Н/Д для массовых конечных точек |
Дескриптор конфигурации состоит из нескольких дескрипторов, объединенных вместе. Каждый из них начинается с полей bLength
и bDescriptorType
чтобы их можно было идентифицировать. Первый интерфейс — это интерфейс HID со связанным дескриптором HID и единственной конечной точкой, используемой для доставки входных событий в операционную систему. Второй интерфейс — это интерфейс, зависящий от поставщика, с двумя конечными точками, которые можно использовать для отправки команд устройству и получения ответов в ответ.
Дескрипторы WebUSB
Хотя WebUSB может работать со многими устройствами без модификации прошивки, дополнительные функции включаются путем маркировки устройства специальными дескрипторами, указывающими на поддержку WebUSB. Например, вы можете указать URL-адрес целевой страницы, на которую браузер может направить пользователя, когда ваше устройство подключено.
Хранилище объектов двоичных устройств (BOS) — это концепция, представленная в USB 3.0, но также перенесенная на устройства USB 2.0 как часть версии 2.1. Объявление поддержки WebUSB начинается с включения следующего дескриптора возможностей платформы в дескриптор BOS:
Ценить | Поле | Описание |
---|---|---|
Дескриптор хранилища объектов двоичного устройства | ||
0x05 | bДлина | Размер этого дескриптора |
0x0F | бдескриптортипе | Дескриптор хранилища объектов двоичного устройства |
0x001D | wTotalLength | Общая длина этой серии дескрипторов |
0x01 | бнумдевицекапс | Количество дескрипторов возможностей устройства в BOS |
Дескриптор возможностей платформы WebUSB | ||
0x18 | bДлина | Размер этого дескриптора |
0x10 | бдескриптортипе | Дескриптор возможностей устройства |
0x05 | бдевкапабилититипе | Дескриптор возможностей платформы |
0x00 | bЗарезервировано | |
{0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65} | ПлатформаВозможностьUUID | GUID дескриптора возможностей платформы WebUSB в формате с прямым порядком байтов |
0x0100 | bcdVersion | Дескриптор WebUSB версии 1.0 |
0x01 | бВендорКод | bЗапросить значение для WebUSB |
0x01 | iLandingPage | URL-адрес целевой страницы |
UUID возможностей платформы идентифицирует это как дескриптор возможностей платформы WebUSB , который предоставляет базовую информацию об устройстве. Чтобы браузер мог получить дополнительную информацию об устройстве, он использует значение bVendorCode
для отправки дополнительных запросов к устройству. В настоящее время указан единственный запрос — GET_URL
, который возвращает дескриптор URL . Они похожи на строковые дескрипторы, но предназначены для кодирования URL-адресов в наименьшее количество байтов. Дескриптор URL-адреса "https://google.com"
будет выглядеть следующим образом:
Ценить | Поле | Описание |
---|---|---|
URL-дескриптор | ||
0x0D | bДлина | Размер этого дескриптора |
0x03 | бдескриптортипе | URL-дескриптор |
0x01 | бСхема | https:// |
"google.com" | URL-адрес | Содержимое URL-адреса в кодировке UTF-8 |
Когда ваше устройство впервые подключается к сети, браузер считывает дескриптор BOS, выдавая стандартную передачу управления GET_DESCRIPTOR
:
bmRequestType | бЗапрос | wValue | wИндекс | wдлина | Данные (ответ) |
---|---|---|---|---|---|
0b10000000 | 0x06 | 0x0F00 | 0x0000 | * | Дескриптор BOS |
Этот запрос обычно выполняется дважды: первый раз с достаточно большим значением wLength
, чтобы хост узнал значение поля wTotalLength
без выполнения большой передачи, а затем еще раз, когда известна полная длина дескриптора.
Если в дескрипторе возможностей платформы WebUSB для поля iLandingPage
установлено ненулевое значение, браузер затем выполняет запрос GET_URL
, специфичный для WebUSB, выдавая передачу управления со значением bRequest
установленным в значение bVendorCode
из дескриптора возможностей платформы, и значением wValue
установленным в значение Значение iLandingPage
. Код запроса GET_URL
( 0x02
) находится в wIndex
:
bmRequestType | бЗапрос | wValue | wИндекс | wдлина | Данные (ответ) |
---|---|---|---|---|---|
0b11000000 | 0x01 | 0x0001 | 0x0002 | * | Дескриптор URL-адреса |
Опять же, этот запрос может быть выдан дважды, чтобы сначала проверить длину считываемого дескриптора.
Особенности платформы
Хотя API WebUSB пытается предоставить согласованный интерфейс для доступа к USB-устройствам, разработчикам все же следует учитывать требования, предъявляемые к приложениям, например, требования к веб-браузерам, для доступа к устройствам.
macOS
Для macOS не требуется ничего особенного. Веб-сайт, использующий WebUSB, может подключиться к устройству и запросить любые интерфейсы, которые не востребованы драйвером ядра или другим приложением.
Линукс
Linux похож на macOS, но по умолчанию большинство дистрибутивов не настраивают учетные записи пользователей с разрешением на открытие USB-устройств. Системный демон udev отвечает за назначение пользователя и группы, которым разрешен доступ к устройству. Подобное правило назначает право собственности на устройство, соответствующее данному поставщику и идентификаторам продукта, группе plugdev
, которая является общей группой для пользователей, имеющих доступ к периферийным устройствам:
SUBSYSTEM=="usb", ATTR{idVendor}=="XXXX", ATTR{idProduct}=="XXXX", GROUP="plugdev"
Замените XXXX
шестнадцатеричным идентификатором производителя и продукта для вашего устройства, например ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e11"
будет соответствовать телефону Nexus One. Для правильного распознавания они должны быть записаны без обычного префикса «0x» и строчных букв. Чтобы найти идентификаторы вашего устройства, запустите инструмент командной строки lsusb
.
Это правило должно быть помещено в файл в каталоге /etc/udev/rules.d
и вступит в силу, как только устройство будет подключено. Нет необходимости перезапускать udev.
Андроид
Платформа Android основана на Linux, но не требует каких-либо изменений в конфигурации системы. По умолчанию браузеру доступно любое устройство, не имеющее встроенного в операционную систему драйвера. Однако разработчики должны знать, что пользователи столкнутся с дополнительным шагом при подключении к устройству. Как только пользователь выберет устройство в ответ на вызов requestDevice()
, Android отобразит запрос с вопросом, разрешить ли Chrome доступ к нему. Это приглашение также появляется снова, если пользователь возвращается на веб-сайт, у которого уже есть разрешение на подключение к устройству, и веб-сайт вызывает open()
.
Кроме того, на Android будет доступно больше устройств, чем на настольной Linux, поскольку по умолчанию включено меньше драйверов. Заметным упущением, например, является класс USB CDC-ACM, обычно реализуемый адаптерами USB-последовательный порт, поскольку в Android SDK нет API для связи с последовательным устройством.
ChromeOS
ChromeOS также основана на Linux и не требует каких-либо изменений в конфигурации системы. Служба Permission_broker контролирует доступ к USB-устройствам и разрешает браузеру доступ к ним, пока существует хотя бы один невостребованный интерфейс.
Окна
Модель драйвера Windows предъявляет дополнительное требование. В отличие от вышеперечисленных платформ возможность открытия USB-устройства из пользовательского приложения не используется по умолчанию, даже если драйвер не загружен. Вместо этого существует специальный драйвер WinUSB, который необходимо загрузить, чтобы обеспечить интерфейс, используемый приложениями для доступа к устройству. Это можно сделать либо с помощью специального файла информации о драйвере (INF), установленного в системе, либо путем изменения встроенного ПО устройства для предоставления дескрипторов совместимости ОС Microsoft во время перечисления.
Информационный файл драйвера (INF)
Файл информации о драйвере сообщает Windows, что делать при первом обнаружении устройства. Поскольку система пользователя уже включает в себя драйвер WinUSB, все, что необходимо, — это INF-файл, чтобы связать вашего поставщика и идентификатор продукта с этим новым правилом установки. Файл ниже представляет собой базовый пример. Сохраните его в файл с расширением .inf
, измените разделы, отмеченные «X», затем щелкните по нему правой кнопкой мыши и выберите «Установить» в контекстном меню.
[Version]
Signature = "$Windows NT$"
Class = USBDevice
ClassGUID = {88BAE032-5A81-49f0-BC3D-A4FF138216D6}
Provider = %ManufacturerName%
CatalogFile = WinUSBInstallation.cat
DriverVer = 09/04/2012,13.54.20.543
; ========== Manufacturer/Models sections ===========
[Manufacturer]
%ManufacturerName% = Standard,NTx86,NTia64,NTamd64
[Standard.NTx86]
%USB\MyCustomDevice.DeviceDesc% = USB_Install,USB\VID_XXXX&PID_XXXX
[Standard.NTia64]
%USB\MyCustomDevice.DeviceDesc% = USB_Install,USB\VID_XXXX&PID_XXXX
[Standard.NTamd64]
%USB\MyCustomDevice.DeviceDesc% = USB_Install,USB\VID_XXXX&PID_XXXX
; ========== Class definition ===========
[ClassInstall32]
AddReg = ClassInstall_AddReg
[ClassInstall_AddReg]
HKR,,,,%ClassName%
HKR,,NoInstallClass,,1
HKR,,IconPath,%REG_MULTI_SZ%,"%systemroot%\system32\setupapi.dll,-20"
HKR,,LowerLogoVersion,,5.2
; =================== Installation ===================
[USB_Install]
Include = winusb.inf
Needs = WINUSB.NT
[USB_Install.Services]
Include = winusb.inf
Needs = WINUSB.NT.Services
[USB_Install.HW]
AddReg = Dev_AddReg
[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
; =================== Strings ===================
[Strings]
ManufacturerName = "Your Company Name Here"
ClassName = "Your Company Devices"
USB\MyCustomDevice.DeviceDesc = "Your Device Name Here"
Раздел [Dev_AddReg]
настраивает набор DeviceInterfaceGUID для устройства. Каждый интерфейс устройства должен иметь GUID, чтобы приложение могло найти его и подключиться к нему через Windows API. Используйте командлет PowerShell New-Guid
или онлайн-инструмент для создания случайного GUID.
В целях разработки инструмент Zadig предоставляет простой интерфейс для замены драйвера, загруженного для интерфейса USB, на драйвер WinUSB.
Дескрипторы совместимости ОС Microsoft
Описанный выше подход с использованием INF-файла является громоздким, поскольку требует предварительной настройки компьютера каждого пользователя. Windows 8.1 и более поздние версии предлагают альтернативу за счет использования пользовательских дескрипторов USB. Эти дескрипторы предоставляют операционной системе Windows информацию при первом подключении устройства, которая обычно включается в INF-файл.
После настройки дескрипторов WebUSB вы также можете легко добавить дескрипторы совместимости ОС Microsoft. Сначала расширите дескриптор BOS этим дополнительным дескриптором возможностей платформы. Обязательно обновите wTotalLength
и bNumDeviceCaps
, чтобы учесть это.
Ценить | Поле | Описание |
---|---|---|
Дескриптор возможностей платформы Microsoft OS 2.0 | ||
0x1C | bДлина | Размер этого дескриптора |
0x10 | бдескриптортипе | Дескриптор возможностей устройства |
0x05 | бдевкапабилититипе | Дескриптор возможностей платформы |
0x00 | bЗарезервировано | |
{0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F} | ПлатформаВозможностьUUID | GUID дескриптора совместимости платформы Microsoft OS 2.0 в формате с прямым порядком байтов. |
0x06030000 | dwWindowsVersion | Минимальная совместимая версия Windows (Windows 8.1) |
0x00B2 | wMSOSDescriptorSetTotalLength | Общая длина набора дескрипторов |
0x02 | bMS_VendorCode | Значение bRequest для получения дополнительных дескрипторов Microsoft |
0x00 | бальтенумкод | Устройство не поддерживает альтернативное перечисление |
Как и в случае с дескрипторами WebUSB, вам необходимо выбрать значение bRequest
, которое будет использоваться при передаче управления, связанной с этими дескрипторами. В этом примере я выбрал 0x02
. 0x07
, помещенный в wIndex
, — это команда для получения набора дескрипторов Microsoft OS 2.0 с устройства.
bmRequestType | бЗапрос | wValue | wИндекс | wдлина | Данные (ответ) |
---|---|---|---|---|---|
0b11000000 | 0x02 | 0x0000 | 0x0007 | * | Набор дескрипторов MS OS 2.0 |
USB-устройство может иметь несколько функций, поэтому первая часть набора дескрипторов описывает, с какой функцией связаны следующие свойства. В приведенном ниже примере настраивается интерфейс 1 составного устройства. Дескриптор предоставляет ОС две важные части информации об этом интерфейсе. Дескриптор совместимого идентификатора сообщает Windows, что это устройство совместимо с драйвером WinUSB. Дескриптор свойства реестра действует аналогично разделу [Dev_AddReg]
в приведенном выше примере INF, устанавливая свойство реестра для назначения этой функции GUID интерфейса устройства.
Ценить | Поле | Описание |
---|---|---|
Заголовок набора дескрипторов Microsoft OS 2.0 | ||
0x000A | wдлина | Размер этого дескриптора |
0x0000 | вдескриптортипе | Дескриптор заголовка набора дескрипторов |
0x06030000 | dwWindowsVersion | Минимальная совместимая версия Windows (Windows 8.1) |
0x00B2 | wTotalLength | Общая длина набора дескрипторов |
Заголовок подмножества конфигурации Microsoft OS 2.0 | ||
0x0008 | wдлина | Размер этого дескриптора |
0x0001 | вдескриптортипе | Описание заголовка подмножества конфигурации. |
0x00 | бConfigurationValue | Применяется к конфигурации 1 (индексируется с 0, несмотря на то, что конфигурации обычно индексируются с 1) |
0x00 | bЗарезервировано | Должен быть установлен на 0 |
0x00A8 | wTotalLength | Общая длина подмножества, включая этот заголовок |
Заголовок подмножества функций Microsoft OS 2.0 | ||
0x0008 | wдлина | Размер этого дескриптора |
0x0002 | вдескриптортипе | Дескриптор заголовка подмножества функции |
0x01 | бПервыйИнтерфейс | Первый интерфейс функции |
0x00 | bЗарезервировано | Должен быть установлен на 0 |
0x00A0 | wSubsetLength | Общая длина подмножества, включая этот заголовок |
Дескриптор идентификатора, совместимый с Microsoft OS 2.0 | ||
0x0014 | wдлина | Размер этого дескриптора |
0x0003 | вдескриптортипе | Совместимый дескриптор идентификатора |
"WINUSB\0\0" | СовместимыйID | Строка ASCII, дополненная до 8 байт |
"\0\0\0\0\0\0\0\0" | СубсовместимыйID | Строка ASCII, дополненная до 8 байт |
Дескриптор свойства реестра Microsoft OS 2.0 | ||
0x0084 | wдлина | Размер этого дескриптора |
0x0004 | вдескриптортипе | Дескриптор свойства реестра |
0x0007 | впропертидататипе | REG_MULTI_SZ |
0x002A | wPropertyNameLength | Длина имени свойства |
"DeviceInterfaceGUIDs\0" | ИмяСвойства | Имя свойства с нулевым терминатором в кодировке UTF-16LE. |
0x0050 | wPropertyDataLength | Длина стоимости недвижимости |
"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}\0\0" | PropertyData | GUID плюс два нулевых терминатора в кодировке UTF-16LE. |
Windows будет запрашивать эту информацию у устройства только один раз. Если устройство не отвечает допустимыми дескрипторами, оно не будет запрашивать повторно при следующем подключении устройства. Microsoft предоставила список записей реестра USB-устройств, описывающих записи реестра, созданные при перечислении устройства. При тестировании удалите записи, созданные для устройства, чтобы заставить Windows снова попытаться прочитать дескрипторы.
Для получения дополнительной информации ознакомьтесь с сообщением в блоге Microsoft о том, как использовать эти дескрипторы.
Примеры
Пример кода, реализующего устройства с поддержкой WebUSB, включающие как дескрипторы WebUSB, так и дескрипторы ОС Microsoft, можно найти в следующих проектах: