Cómo compilar un dispositivo para WebUSB

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.

Captura de pantalla de la notificación de WebUSB en Chrome
Notificación de WebUSB.

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: