Compila un dispositivo para aprovechar al máximo la API de WebUSB.
En este artículo, se explica cómo crear un dispositivo para aprovechar al máximo el API de WebUSB: Para ver una breve introducción a la API, consulta Cómo acceder a dispositivos USB en la Web.
Información general
El bus universal en serie (USB) se ha convertido en la interfaz física más común para conectando periféricos a computadoras de escritorio y dispositivos móviles. Además de definir las características eléctricas del bus y un modelo general para comunicación con un dispositivo, las especificaciones de USB incluyen un conjunto de elementos de clase y las especificaciones del servicio. Estos son modelos generales para clases particulares de dispositivos, como como almacenamiento, audio, video, redes, etc., que los fabricantes de dispositivos pueden implementar. La ventaja de estas especificaciones de clase de dispositivo es que el proveedor de sistemas operativos puede implementar un solo controlador basado en la clase especificación (un "controlador de clase") y cualquier dispositivo que implemente esa clase no es compatible. Esto fue una gran mejora respecto de todos los fabricantes que necesitaban escribir sus propios controladores de dispositivo.
Sin embargo, algunos dispositivos no encajan en una de estas clases de dispositivos estandarizadas. R el fabricante puede optar por etiquetar su dispositivo como una implementación del específica del proveedor. En este caso, el sistema operativo elige qué dispositivo que cargue el controlador según la información proporcionada en el paquete del controlador del proveedor normalmente, es un conjunto de IDs de productos y proveedores que se sabe que implementan un protocolo específico específico del proveedor.
Otra característica del USB es que los dispositivos pueden proporcionar múltiples interfaces para el host al que están conectados. Cada interfaz puede implementar estandarizada o específica del proveedor. Cuando un sistema operativo elige controladores adecuados para manejar el dispositivo. Cada interfaz puede reclamarse por un controlador. Por ejemplo, una cámara web con USB suele proporcionar dos interfaces, una implementando la clase de video USB (para la cámara) y otro que implementa el USB de audio (para el micrófono). El sistema operativo no carga una sola "controlador de cámara web" sino que carga controladores de clase de audio y video independientes que asumen la responsabilidad de las distintas funciones del dispositivo. Esta la composición de las clases de interfaz proporciona una mayor flexibilidad.
Conceptos básicos de API
Muchas de las clases de USB estándar tienen las APIs web correspondientes. Por ejemplo, un
puede capturar videos desde un dispositivo de clase de video con getUserMedia()
.
o recibir eventos de entrada de un dispositivo con clase de interfaz humana (HID) escuchando
para KeyboardEvents o PointerEvents, o bien con el Gamepad o el
API de WebHID.
No todos los dispositivos implementan una definición de clase estandarizada, no todos
implementan funciones que corresponden a las APIs de plataformas web existentes. Cuándo
este es el caso en que la API de WebUSB puede llenar esa brecha proporcionando una manera para que los sitios
para reclamar una interfaz específica del proveedor e implementar la asistencia desde el
dentro de su página.
Los requisitos específicos para que un dispositivo sea accesible a través de WebUSB varían levemente de una plataforma a otra debido a las diferencias en la forma en que los sistemas operativos administran los puertos USB pero el requisito básico es que un dispositivo no tenga ya conductor que reclama la interfaz que la página desea controlar. Esto puede ser un controlador de clase genérico proporcionado por el proveedor del SO o un controlador de dispositivo proporcionado por el proveedor. Como los dispositivos USB pueden proporcionar varias interfaces, cada una de las cuales puede tienen su propio controlador, es posible crear un dispositivo para el que algunas interfaces un conductor, y el navegador puede acceder a los demás.
Por ejemplo, un teclado USB de alta gama puede proporcionar una interfaz de clase HID que el subsistema de entrada del sistema operativo y una política que permanece disponible para WebUSB para que la use una herramienta de configuración. Esta herramienta en el sitio web del fabricante, lo que le permite al usuario cambiar aspectos del comportamiento del dispositivo, como las teclas de macro y los efectos de luz sin instalar cualquier software específico de la plataforma. El descriptor de configuración de este dispositivo para que se vea algo así:
Valor | Campo | Descripción |
---|---|---|
Descriptor de configuración | ||
0x09 |
bLength | Tamaño de este descriptor |
0x02 |
bDescriptorType | Descriptor de configuración |
0x0039 |
wTotalLength | Longitud total de esta serie de descriptores |
0x02 |
bNumInterfaces | Cantidad de interfaces |
0x01 |
bConfigurationValue | Configuration 1 |
0x00 |
iConfiguration | Nombre de la configuración (ninguna) |
0b1010000 |
bmAttributes | Dispositivo autónomo con activación remota |
0x32 |
bMaxPower | La potencia máxima se expresa en incrementos de 2 mA |
Descriptor de interfaz | ||
0x09 |
bLength | Tamaño de este descriptor |
0x04 |
bDescriptorType | Descriptor de interfaz |
0x00 |
bInterfaceNumber | Interfaz 0 |
0x00 |
bAlternateSetting | Configuración alternativa 0 (predeterminada) |
0x01 |
bNumEndpoints | 1 extremo |
0x03 |
bInterfaceClass | Clase de interfaz HID |
0x01 |
bInterfaceSubClass | Subclase de interfaz de inicio |
0x01 |
bInterfaceProtocol | Teclado |
0x00 |
iInterface | Nombre de la interfaz (ninguno) |
Descriptor HID | ||
0x09 |
bLength | Tamaño de este descriptor |
0x21 |
bDescriptorType | Descriptor HID |
0x0101 |
bcdHID | Versión 1.1 de HID |
0x00 |
bCountryCode | País de segmentación del hardware |
0x01 |
bNumDescriptors | Cantidad de descriptores de clase HID a seguir |
0x22 |
bDescriptorType | Tipo de descriptor de informe |
0x003F |
wDescriptorLength | Longitud total del descriptor de informes |
Descriptor de extremos | ||
0x07 |
bLength | Tamaño de este descriptor |
0x05 |
bDescriptorType | Descriptor de extremos |
0b10000001 |
bEndpointAddress | Extremo 1 (India) |
0b00000011 |
bmAttributes | Interrumpir |
0x0008 |
wMaxPacketSize | Paquetes de 8 bytes |
0x0A |
bInterval | Intervalo de 10 ms |
Descriptor de interfaz | ||
0x09 |
bLength | Tamaño de este descriptor |
0x04 |
bDescriptorType | Descriptor de interfaz |
0x01 |
bInterfaceNumber | Interfaz 1 |
0x00 |
bAlternateSetting | Configuración alternativa 0 (predeterminada) |
0x02 |
bNumEndpoints | 2 extremos |
0xFF |
bInterfaceClass | Clase de interfaz específica del proveedor |
0x00 |
bInterfaceSubClass | |
0x00 |
bInterfaceProtocol | |
0x00 |
iInterface | Nombre de la interfaz (ninguno) |
Descriptor de extremos | ||
0x07 |
bLength | Tamaño de este descriptor |
0x05 |
bDescriptorType | Descriptor de extremos |
0b10000010 |
bEndpointAddress | Extremo 1 (India) |
0b00000010 |
bmAttributes | Masiva |
0x0040 |
wMaxPacketSize | Paquetes de 64 bytes |
0x00 |
bInterval | N/A para extremos masivos |
Descriptor de extremos | ||
0x07 |
bLength | Tamaño de este descriptor |
0x05 |
bDescriptorType | Descriptor de extremos |
0b00000011 |
bEndpointAddress | Extremo 3 (OUT) |
0b00000010 |
bmAttributes | Masiva |
0x0040 |
wMaxPacketSize | Paquetes de 64 bytes |
0x00 |
bInterval | N/A para extremos masivos |
El descriptor de configuración consta de varios descriptores concatenados
entre sí. Cada uno comienza con los campos bLength
y bDescriptorType
para que
que se puedan identificar. La primera interfaz es una interfaz HID con una interfaz
descriptor HID y un único extremo que se usa para entregar eventos de entrada al
un sistema operativo completo. La segunda es una interfaz específica del proveedor con dos
extremos que pueden usarse para enviar comandos al dispositivo y recibir respuestas
a cambio.
Descriptores de WebUSB
Si bien WebUSB puede funcionar con muchos dispositivos sin modificaciones de firmware, para habilitar la funcionalidad adicional marcando el dispositivo con descriptores que indican compatibilidad con WebUSB Por ejemplo, puedes especificar un URL de página de destino a la que el navegador puede dirigir al usuario cuando su dispositivo enchufado.
El Almacén de objetos de dispositivos binarios (BOS) es un concepto que se introdujo en USB 3.0, pero tiene también cuentan con portabilidad a versiones anteriores a dispositivos USB 2.0 como parte de la versión 2.1. Declarando La compatibilidad con WebUSB comienza con la inclusión de las siguientes capacidades de plataforma: Descriptor en el descriptor de BOS:
Valor | Campo | Descripción |
---|---|---|
Descriptor de almacén de objetos de dispositivos binarios | ||
0x05 |
bLength | Tamaño de este descriptor |
0x0F |
bDescriptorType | Descriptor de almacén de objetos de dispositivos binarios |
0x001D |
wTotalLength | Longitud total de esta serie de descriptores |
0x01 |
bNumDeviceCaps | Cantidad de descriptores de capacidad del dispositivo en el BOS |
Descriptor de capacidades de la plataforma WebUSB | ||
0x18 |
bLength | Tamaño de este descriptor |
0x10 |
bDescriptorType | Descriptor de capacidades del dispositivo |
0x05 |
bDevCapabilityType | Descriptor de capacidades de la plataforma |
0x00 |
bReserved | |
{0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65} |
PlatformCapablityUUID | GUID del descriptor de capacidad de la plataforma WebUSB en formato small-endian |
0x0100 |
bcdVersion | Descriptor de WebUSB versión 1.0 |
0x01 |
bVendorCode | Valor de bRequest para WebUSB |
0x01 |
iLandingPage | URL de la página de destino |
El UUID de capacidad de plataforma lo identifica como una Capacidad de plataforma de WebUSB
descriptor, que proporciona información básica sobre el dispositivo. Para el navegador
Para recuperar más información sobre el dispositivo en el que usa el valor bVendorCode
enviar solicitudes adicionales al dispositivo. La única solicitud especificada actualmente es
GET_URL
, que muestra un descriptor de URL Son similares a las cadenas de texto
descriptores de archivo, pero que están diseñados para codificar URL con la menor cantidad de bytes. Una URL
descriptor de "https://google.com"
se vería de la siguiente manera:
Valor | Campo | Descripción |
---|---|---|
Descriptor de URL | ||
0x0D |
bLength | Tamaño de este descriptor |
0x03 |
bDescriptorType | Descriptor de URL |
0x01 |
bScheme | https:// |
"google.com" |
URL | Contenido de la URL con codificación UTF-8 |
Cuando se conecta el dispositivo por primera vez, el navegador lee el descriptor BOS.
emite esta transferencia de control estándar GET_DESCRIPTOR
:
bmRequestType | bRequest | wValue | wIndex | wLength | Datos (respuesta) |
---|---|---|---|---|---|
0b10000000 |
0x06 |
0x0F00 |
0x0000 |
* | El descriptor de BOS |
Por lo general, esta solicitud se realiza dos veces, la primera vez con un wLength
lo suficientemente grande.
para que el host averigüe el valor del campo wTotalLength
sin
comprometerse a realizar una transferencia grande y, otra vez, cuando la longitud completa del descriptor sea
conocidos.
Si el descriptor de capacidades de la plataforma WebUSB tiene el campo iLandingPage
configurado como
un valor distinto de cero, el navegador luego realiza una solicitud GET_URL
específica de WebUSB
a través de la emisión de una transferencia de control con bRequest
establecido en el valor bVendorCode
del descriptor de capacidades de la plataforma y wValue
establecido en iLandingPage
valor. El código de solicitud para GET_URL
(0x02
) va en wIndex
:
bmRequestType | bRequest | wValue | wIndex | wLength | Datos (respuesta) |
---|---|---|---|---|---|
0b11000000 |
0x01 |
0x0001 |
0x0002 |
* | El descriptor de URL |
Nuevamente, esta solicitud puede emitirse dos veces para sondear primero la longitud del descriptor que se está leyendo.
Consideraciones específicas de la plataforma
Si bien la API de WebUSB intenta proporcionar una interfaz coherente para acceder Los desarrolladores de dispositivos USB deben estar al tanto de los requisitos que se imponen a aplicaciones, como los requisitos de un navegador web para acceder a los dispositivos.
macOS
No se necesita nada especial para macOS. Un sitio web que usa WebUSB puede conectarse a el dispositivo y reclamar interfaces que no haya reclamado un controlador de kernel o en otra aplicación.
Linux
Linux es como macOS, pero, de forma predeterminada, la mayoría de las distribuciones
con permiso para abrir dispositivos USB. Un daemon del sistema llamado udev se
responsable de asignar al usuario y al grupo autorizados para acceder a un dispositivo. Una regla
como esta asignarán la propiedad de un dispositivo que coincida con el proveedor determinado y
IDs de productos al grupo plugdev
, que es un grupo común para los usuarios con acceso
a los periféricos:
SUBSYSTEM=="usb", ATTR{idVendor}=="XXXX", ATTR{idProduct}=="XXXX", GROUP="plugdev"
Reemplaza XXXX
por los IDs del producto y del proveedor hexadecimales de tu dispositivo.
p.ej., ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e11"
coincidiría con un Nexus One
teléfono. Se deben escribir sin el “0x” habitual prefijo y todo en minúsculas
se reconozcan correctamente. Para encontrar los IDs de tu dispositivo, ejecuta la línea de comandos
herramienta lsusb
.
Esta regla debe colocarse en un archivo en el directorio /etc/udev/rules.d
y
se aplica tan pronto como se conecta el dispositivo. No es necesario reiniciar
udev.
Android
La plataforma de Android se basa en Linux, pero no requiere ninguna modificación para
configuración del sistema. De forma predeterminada, cualquier dispositivo que no tenga un controlador integrado
al sistema operativo está disponible para el navegador. Los desarrolladores deben
Sin embargo, ten en cuenta que los usuarios encontrarán un paso adicional cuando se conecten a
el dispositivo. Una vez que un usuario selecciona un dispositivo en respuesta a una llamada a
requestDevice()
, Android mostrará un mensaje en el que se te preguntará si deseas permitirlo.
Chrome para acceder. Este mensaje también volverá a aparecer si un usuario regresa a un sitio web
que ya tiene permiso para conectarse a un dispositivo y el sitio web llama
open()
Además, se podrá acceder a más dispositivos en Android que en Linux de escritorio. porque se incluyen menos conductores de forma predeterminada. Una omisión notable, por ejemplo, es la clase USB CDC-ACM que suelen implementar los adaptadores USB a serie no hay una API en el SDK de Android para comunicarse con un dispositivo en serie.
ChromeOS
ChromeOS también se basa en Linux y no requiere ninguna modificación. a la configuración del sistema. El servicio permission_broker controla el acceso a los datos dispositivos y permitirá que el navegador acceda a ellos siempre y cuando haya al menos una interfaz no reclamada.
Windows
El modelo del controlador de Windows incluye un requisito adicional. A diferencia de plataformas por encima de la capacidad de abrir un dispositivo USB desde una aplicación de usuario no es el valor predeterminado, incluso si no hay ningún controlador cargado. En cambio, hay una estrategia WinUSB, que se debe cargar para proporcionar la interfaz usan las aplicaciones para acceder al dispositivo. Esto se puede hacer con un backend de información del controlador (INF) instalado en el sistema o modificando el dispositivo para proporcionar los descriptores de compatibilidad de Microsoft OS durante enumeración.
Archivo de información del controlador (INF)
Un archivo de información del controlador le indica a Windows qué hacer cuando encuentra un dispositivo
por primera vez. Como el sistema del usuario ya incluye el controlador WinUSB
todo lo que se necesita es que el archivo INF asocie tu ID del producto y tu proveedor
con esta nueva regla de instalación. El siguiente archivo es un ejemplo básico. Guárdalo en un
con la extensión .inf
, cambia las secciones marcadas con "X" y, luego, hacia la derecha
haz clic en él y elige "Instalar" en el menú contextual.
[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"
La sección [Dev_AddReg]
configura el conjunto de DeviceInterfaceGUIDs para el
dispositivo. Cada interfaz de dispositivo debe tener un GUID para que una aplicación pueda
encontrarlo y conectarse a él a través de la API de Windows. Usa el PowerShell New-Guid
.
cmdlet o una herramienta en línea para generar un GUID aleatorio.
Para fines de desarrollo, la herramienta Zadig proporciona una interfaz sencilla para y reemplaza el controlador cargado para una interfaz USB por el controlador WinUSB.
Descriptores de compatibilidad del SO Microsoft
El enfoque de archivo INF anterior es engorroso porque requiere configurar cada la máquina del usuario con anticipación. Windows 8.1 y las versiones posteriores ofrecen una alternativa a través del uso de descriptores USB personalizados. Estos descriptores proporcionan información al sistema operativo Windows, cuando el dispositivo se conecta por primera vez, que normalmente se incluyen en el archivo INF.
Una vez que hayas configurado los descriptores de WebUSB, podrás agregar fácilmente el SO de Microsoft
de compatibilidad. Primero, extiende el descriptor BOS con este
descriptor de capacidad de plataforma adicional. Asegúrate de actualizar wTotalLength
y bNumDeviceCaps
para compensarlo.
Valor | Campo | Descripción |
---|---|---|
Descriptor de capacidades de la plataforma Microsoft OS 2.0 | ||
0x1C |
bLength | Tamaño de este descriptor |
0x10 |
bDescriptorType | Descriptor de capacidades del dispositivo |
0x05 |
bDevCapabilityType | Descriptor de capacidades de la plataforma |
0x00 |
bReserved | |
{0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F} |
PlatformCapablityUUID | GUID del descriptor de compatibilidad de la plataforma Microsoft OS 2.0 en formato Little endian |
0x06030000 |
dwWindowsVersion | Versión mínima de Windows compatible (Windows 8.1) |
0x00B2 |
wMSOSDescriptorSetTotalLength | Longitud total del conjunto de descriptores |
0x02 |
bMS_VendorCode | Valor de bRequest para recuperar más descriptores de Microsoft |
0x00 |
bAltEnumCode | El dispositivo no admite una enumeración alternativa |
Al igual que con los descriptores de WebUSB, debes elegir un valor de bRequest
para que lo use.
controlar las transferencias relacionadas con estos descriptores. En este ejemplo, elegí
0x02
0x07
, ubicado en wIndex
, es el comando para recuperar el SO Microsoft
2.0 Conjunto de descriptores del dispositivo.
bmRequestType | bRequest | wValue | wIndex | wLength | Datos (respuesta) |
---|---|---|---|---|---|
0b11000000 |
0x02 |
0x0000 |
0x0007 |
* | Conjunto de descriptores de MS OS 2.0 |
Un dispositivo USB puede tener varias funciones. Por lo tanto, la primera parte del descriptor
describe con qué función se asocian las siguientes propiedades. El
en el siguiente ejemplo, se configura la interfaz 1 de un dispositivo compuesto. El descriptor da
dos datos importantes sobre esta interfaz. La plataforma
El descriptor de ID le indica a Windows que este dispositivo es compatible con el puerto WinUSB
controlador. El descriptor de propiedades de registro funciona de manera similar al
Sección [Dev_AddReg]
del ejemplo de INF anterior, configurando una propiedad de registro como
asigna a esta función un GUID de interfaz de dispositivo.
Valor | Campo | Descripción |
---|---|---|
Encabezado del conjunto de descriptores de Microsoft OS 2.0 | ||
0x000A |
wLength | Tamaño de este descriptor |
0x0000 |
wDescriptorType | Descriptor de encabezado del conjunto de descriptores |
0x06030000 |
dwWindowsVersion | Versión mínima de Windows compatible (Windows 8.1) |
0x00B2 |
wTotalLength | Longitud total del conjunto de descriptores |
Encabezado del subconjunto de configuración de Microsoft OS 2.0 | ||
0x0008 |
wLength | Tamaño de este descriptor |
0x0001 |
wDescriptorType | Desc. del encabezado del subconjunto de configuración |
0x00 |
bConfigurationValue | Se aplica a la configuración 1 (indexada desde 0 a pesar de los parámetros de configuración normalmente indexada desde 1) |
0x00 |
bReserved | Se debe establecer en 0 |
0x00A8 |
wTotalLength | Longitud total del subconjunto que incluye este encabezado |
Encabezado del subconjunto de funciones de Microsoft OS 2.0 | ||
0x0008 |
wLength | Tamaño de este descriptor |
0x0002 |
wDescriptorType | Descriptor de encabezado del subconjunto de funciones |
0x01 |
bFirstInterface | Primera interfaz de la función |
0x00 |
bReserved | Se debe establecer en 0 |
0x00A0 |
wSubsetLength | Longitud total del subconjunto que incluye este encabezado |
Descriptor de ID compatible con Microsoft OS 2.0 | ||
0x0014 |
wLength | Tamaño de este descriptor |
0x0003 |
wDescriptorType | Descriptor de ID compatible |
"WINUSB\0\0" |
CompatibileID | Cadena ASCII con relleno de 8 bytes |
"\0\0\0\0\0\0\0\0" |
SubCompatibleID | Cadena ASCII con relleno de 8 bytes |
Descriptor de propiedades del registro de Microsoft OS 2.0 | ||
0x0084 |
wLength | Tamaño de este descriptor |
0x0004 |
wDescriptorType | Descriptor de propiedades de registro |
0x0007 |
wPropertyDataType | REG_MULTI_SZ |
0x002A |
wPropertyNameLength | Longitud del nombre de la propiedad |
"DeviceInterfaceGUIDs\0" |
PropertyName | Nombre de la propiedad con terminador nulo codificado en UTF-16LE |
0x0050 |
wPropertyDataLength | Longitud del valor de la propiedad |
"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}\0\0" |
PropertyData | GUID más dos terminadores nulos codificados en UTF-16LE |
Windows solo consultará esta información al dispositivo una vez. Si el dispositivo no no responda con descriptores válidos, no se volverá a preguntar la próxima vez que dispositivo está conectado. Microsoft proporcionó una lista de registros de dispositivos USB Entradas que describen las entradas de registro creadas al enumerar un dispositivo Cuándo eliminar las entradas creadas para un dispositivo a fin de forzar que Windows intente leer los descriptores nuevamente.
Para obtener más información, consulta la entrada de blog de Microsoft sobre cómo usar estas funciones descriptores de archivo.
Ejemplos
Ejemplo de código en el que se implementan dispositivos compatibles con WebUSB que incluyen WebUSB y los descriptores del SO de Microsoft se encuentran en estos proyectos: