Crie um dispositivo para aproveitar ao máximo a API WebUSB.
Este artigo explica como criar um dispositivo para aproveitar ao máximo a API WebUSB. Para uma breve introdução à API, veja Acessar dispositivos USB na Web.
Contexto
O USB (Universal Serial Bus) tornou-se a interface física mais comum para conectar periféricos a computadores e dispositivos móveis de computação. Além de definir as características elétricas do ônibus e um modelo geral para comunicando com um dispositivo, as especificações de USB incluem um conjunto de classes especificações. Esses são modelos gerais para classes específicas de dispositivos, como armazenamento, áudio, vídeo, rede etc. que os fabricantes de dispositivos podem implementar. A vantagem dessas especificações de classe de dispositivo é que um fornecedor de sistema operacional pode implementar um único driver com base na classe (um "driver de classe") e qualquer dispositivo que implemente essa classe será suporte. Essa foi uma grande melhoria em relação a todos os fabricantes que precisavam escrever os próprios drivers de dispositivo.
No entanto, alguns dispositivos não se encaixam nessas classes padronizadas. Um o fabricante pode optar por rotular seus dispositivos como em uma classe específica de fornecedor. Nesse caso, o sistema operacional escolhe o dispositivo o driver seja carregado com base nas informações fornecidas no pacote de drivers do fornecedor, normalmente um conjunto de IDs de produto e fornecedor que são conhecidos por implementar uma protocolo específico do fornecedor.
Outra característica do USB é que os dispositivos podem fornecer várias interfaces para ao host ao qual estão conectados. Cada interface pode implementar uma classe padronizada ou ser específico do fornecedor. Quando um sistema operacional escolhe os drivers certos para o dispositivo. Cada interface pode ser reivindicada por um motorista. Por exemplo, uma webcam USB normalmente tem duas interfaces, uma implementando a classe de vídeo USB (para a câmera) e outra implementando a classe de áudio (para o microfone). O sistema operacional não carrega um único "driver da webcam" mas carrega drivers independentes de classe de vídeo e áudio que assumem a responsabilidade pelas funções separadas do dispositivo. Isso composição de classes de interface oferece maior flexibilidade.
Princípios básicos da API
Muitas das classes USB padrão têm APIs da Web correspondentes. Por exemplo,
página pode capturar vídeo de um dispositivo de classe de vídeo usando getUserMedia()
ou receber eventos de entrada de um dispositivo de classe de interface humana (HID) ouvindo
para KeyboardEvents ou PointerEvents, ou ao usar o Gamepad ou o
API WebHID.
Assim como nem todos os dispositivos implementam uma definição de classe padronizada, nem todos
dispositivos implementam recursos que correspondem às APIs de plataforma web existentes. Quando
neste caso, a API WebUSB pode preencher essa lacuna oferecendo uma maneira
reivindicar uma interface específica do fornecedor e implementar o suporte diretamente
dentro de suas páginas.
Os requisitos específicos para que um dispositivo possa ser acessado via WebUSB variam um pouco de plataforma para plataforma devido a diferenças na forma como os sistemas operacionais gerenciam USB do Google, mas o requisito básico é que ele não tenha um que reivindica a interface que a página quer controlar. Pode ser um driver de classe genérica fornecido pelo fornecedor do SO ou um driver de dispositivo fornecido pelo com o fornecedor. Como os dispositivos USB podem fornecer várias interfaces, cada uma delas pode tem driver próprio, é possível criar um dispositivo para o qual algumas interfaces são reivindicados por um motorista, e os demais podem ser acessados pelo navegador.
Por exemplo, um teclado USB de última geração pode fornecer uma interface de classe HID que será reivindicado pelo subsistema de entrada do sistema operacional e por um nome de que continua disponível para o WebUSB para uso por uma ferramenta de configuração. Isso ferramenta pode ser exibida no site do fabricante, permitindo que o usuário altere aspectos do comportamento do dispositivo, como teclas macro e efeitos de iluminação sem sem instalar softwares específicos da plataforma. Esse descritor de configuração de dispositivo será mais ou menos assim:
Valor | Campo | Descrição |
---|---|---|
Descritor de configuração | ||
0x09 |
bLength | Tamanho deste descritor |
0x02 |
bDescriptorType | Descritor de configuração |
0x0039 |
wTotalLength | Comprimento total dessa série de descritores |
0x02 |
bNumInterfaces | Número de interfaces |
0x01 |
bConfigurationValue | Configuração 1 |
0x00 |
iConfiguration | Nome da configuração (nenhum) |
0b1010000 |
bmAttributes | Dispositivo autônomo com ativação remota |
0x32 |
bMaxPower | A potência máxima é expressa em incrementos de 2 mA. |
Descritor da interface | ||
0x09 |
bLength | Tamanho deste descritor |
0x04 |
bDescriptorType | Descritor da interface |
0x00 |
bInterfaceNumber | Interface 0 |
0x00 |
bAlternateSetting | Configuração alternativa 0 (padrão) |
0x01 |
bNumEndpoints | 1 endpoint |
0x03 |
bInterfaceClass | Classe de interface HID |
0x01 |
bInterfaceSubClass | Subclasse da interface de inicialização |
0x01 |
bInterfaceProtocol | Teclado |
0x00 |
iInterface | Nome da interface (nenhum) |
Descritor HID | ||
0x09 |
bLength | Tamanho deste descritor |
0x21 |
bDescriptorType | Descritor HID |
0x0101 |
bcdHID | HID versão 1.1 |
0x00 |
bCountryCode | País de destino do hardware |
0x01 |
bNumDescriptors | Número de descritores de classe HID a serem seguidos |
0x22 |
bDescriptorType | Tipo de descritor do relatório |
0x003F |
wDescriptorLength | Comprimento total do descritor do relatório |
Descritor de endpoint | ||
0x07 |
bLength | Tamanho deste descritor |
0x05 |
bDescriptorType | Descritor de endpoint |
0b10000001 |
bEndpointAddress | Endpoint 1 (IN) |
0b00000011 |
bmAttributes | Interromper |
0x0008 |
wMaxPacketSize | Pacotes de 8 bytes |
0x0A |
bInterval | Intervalo de 10 ms |
Descritor da interface | ||
0x09 |
bLength | Tamanho deste descritor |
0x04 |
bDescriptorType | Descritor da interface |
0x01 |
bInterfaceNumber | Interface 1 |
0x00 |
bAlternateSetting | Configuração alternativa 0 (padrão) |
0x02 |
bNumEndpoints | 2 endpoints |
0xFF |
bInterfaceClass | Classe de interface específica do fornecedor |
0x00 |
bInterfaceSubClass | |
0x00 |
bInterfaceProtocol | |
0x00 |
iInterface | Nome da interface (nenhum) |
Descritor de endpoint | ||
0x07 |
bLength | Tamanho deste descritor |
0x05 |
bDescriptorType | Descritor de endpoint |
0b10000010 |
bEndpointAddress | Endpoint 1 (IN) |
0b00000010 |
bmAttributes | Em massa |
0x0040 |
wMaxPacketSize | Pacotes de 64 bytes |
0x00 |
bInterval | N/A para endpoints em massa |
Descritor de endpoint | ||
0x07 |
bLength | Tamanho deste descritor |
0x05 |
bDescriptorType | Descritor de endpoint |
0b00000011 |
bEndpointAddress | Endpoint 3 (SAINDO) |
0b00000010 |
bmAttributes | Em massa |
0x0040 |
wMaxPacketSize | Pacotes de 64 bytes |
0x00 |
bInterval | N/A para endpoints em massa |
O descritor de configuração consiste em vários descritores concatenados
juntas. Cada um começa com os campos bLength
e bDescriptorType
para que
possam ser identificados. A primeira interface é uma interface HID com uma interface
Descritor HID e um único endpoint usado para entregar eventos de entrada para o
operacional principal. A segunda interface é específica para fornecedores, com duas
endpoints que podem ser usados para enviar comandos ao dispositivo e receber respostas
em troca.
Descritores WebUSB
Embora a WebUSB funcione com muitos dispositivos sem modificações no firmware, Para ativar esse recurso, marque o dispositivo com informações descritores que indicam compatibilidade com WebUSB. Por exemplo, é possível especificar URL da página de destino para a qual o navegador pode direcionar o usuário quando o dispositivo está conectado.
O armazenamento de objetos binários (BOS, na sigla em inglês) de dispositivos binários é um conceito introduzido no USB 3.0, mas também passou por backport para dispositivos USB 2.0 como parte da versão 2.1. Declaração o suporte para WebUSB começa com a inclusão da seguinte capacidade da plataforma Descritor no BOS:
Valor | Campo | Descrição |
---|---|---|
Descritor de armazenamento de objetos de dispositivo binário | ||
0x05 |
bLength | Tamanho deste descritor |
0x0F |
bDescriptorType | Descritor de armazenamento de objetos de dispositivo binário |
0x001D |
wTotalLength | Comprimento total dessa série de descritores |
0x01 |
bNumDeviceCaps | Número de descritores de capacidade do dispositivo no BOS |
Descritor de capacidade da plataforma WebUSB | ||
0x18 |
bLength | Tamanho deste descritor |
0x10 |
bDescriptorType | Descritor de capacidade do dispositivo |
0x05 |
bDevCapabilityType | Descritor de recursos da plataforma |
0x00 |
bReserved | |
{0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65} |
PlatformCapablityUUID | Descritor de capacidade da plataforma WebUSB GUID em formato pouco-endian |
0x0100 |
bcdVersion | Descritor WebUSB versão 1.0 |
0x01 |
bVendorCode | Valor de bRequest para WebUSB |
0x01 |
iLandingPage | URL da página de destino |
O UUID da capacidade da plataforma identifica esse recurso como uma Capacidade da plataforma WebUSB
descritor, que fornece informações básicas sobre o dispositivo. Para o navegador
para buscar mais informações sobre o dispositivo em que o valor bVendorCode
é usado.
emitir solicitações adicionais ao dispositivo. A única solicitação especificada atualmente é
GET_URL
, que retorna um descritor de URL. Elas são semelhantes às strings
descritores, mas são projetados para codificar URLs com menos bytes. Um URL
descritor de "https://google.com"
ficaria assim:
Valor | Campo | Descrição |
---|---|---|
Descritor do URL | ||
0x0D |
bLength | Tamanho deste descritor |
0x03 |
bDescriptorType | Descritor do URL |
0x01 |
bScheme | https:// |
"google.com" |
URL | Conteúdo de URL codificado em UTF-8 |
Quando seu dispositivo é conectado pela primeira vez, o navegador lê o descritor BOS
emitindo esta transferência de controle do GET_DESCRIPTOR
padrão:
bmRequestType | bRequest | wValue | wIndex | wLength | Dados (resposta) |
---|---|---|---|---|---|
0b10000000 |
0x06 |
0x0F00 |
0x0000 |
* | O descritor BOS |
Essa solicitação geralmente é feita duas vezes, a primeira vez com um wLength
grande o suficiente
para que o host descubra o valor do campo wTotalLength
sem
fazer uma transferência grande e novamente quando o comprimento completo do descritor for
conhecidos.
Se o descritor de recursos da plataforma WebUSB tiver o campo iLandingPage
definido como
um valor diferente de zero, o navegador executa uma solicitação GET_URL
específica de WebUSB
emitindo uma transferência de controle com o bRequest
definido como o valor bVendorCode
do descritor de capacidade da plataforma e o wValue
definido como iLandingPage
. O código de solicitação para GET_URL
(0x02
) fica em wIndex
:
bmRequestType | bRequest | wValue | wIndex | wLength | Dados (resposta) |
---|---|---|---|---|---|
0b11000000 |
0x01 |
0x0001 |
0x0002 |
* | O descritor de URL |
Novamente, essa solicitação pode ser emitida duas vezes para a primeira sondagem do descritor que está sendo lido.
Considerações específicas da plataforma
Enquanto a API WebUSB tenta fornecer uma interface consistente para acessar Os desenvolvedores de dispositivos USB ainda devem estar cientes dos requisitos impostos aos aplicativos, como requisitos de navegadores da Web, para acessar os dispositivos.
macOS
Nada de especial é necessário para o macOS. Um site que usa WebUSB pode se conectar ao o dispositivo e reivindicar quaisquer interfaces que não sejam reivindicadas por um driver de kernel ou outro aplicativo.
Linux
O Linux é como o macOS, mas, por padrão, a maioria das distribuições não configura
contas com permissão para abrir dispositivos USB. Um daemon do sistema chamado udev é
responsável por atribuir o usuário e o grupo com permissão para acessar um dispositivo. Uma regra
como isso atribui a propriedade de um dispositivo correspondente ao fornecedor e
IDs de produtos ao grupo plugdev
, que é um grupo comum de usuários com acesso
a periféricos:
SUBSYSTEM=="usb", ATTR{idVendor}=="XXXX", ATTR{idProduct}=="XXXX", GROUP="plugdev"
Substitua XXXX
pelos IDs de fornecedor e produto hexadecimais do seu dispositivo.
Por exemplo: ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e11"
corresponderia a um Nexus One
celular. Eles devem ser escritos sem o "0x" normal, prefixo e todos em minúsculas
para ser reconhecido corretamente. Para encontrar os IDs do seu dispositivo, execute a linha de comando
ferramenta lsusb
.
Essa regra deve ser colocada em um arquivo no diretório /etc/udev/rules.d
e
entra em vigor assim que o dispositivo é conectado. Não é necessário reiniciar
udev.
Android
A plataforma Android é baseada em Linux, mas não requer nenhuma modificação para
configuração do sistema. Por padrão, qualquer dispositivo que não tenha um driver integrado.
no sistema operacional está disponível para o navegador. Os desenvolvedores devem ser
mas que os usuários encontrarão uma etapa adicional ao se conectarem
o dispositivo. Quando um usuário seleciona um dispositivo em resposta a uma chamada para
requestDevice()
, o Android vai mostrar uma solicitação perguntando se você quer permitir
Chrome para acessá-lo. Essa solicitação também reaparece se um usuário retornar a um site
que já tem permissão para se conectar a um dispositivo e o site chamar
open()
Além disso, mais dispositivos estarão acessíveis no Android do que no Linux para computador porque há menos drivers incluídos por padrão. Uma omissão importante, por exemplo, é a classe USB CDC-ACM geralmente implementada por adaptadores USB para serial, não há uma API no SDK do Android para comunicação com um dispositivo serial.
ChromeOS
O ChromeOS também é baseado no Linux e também não requer nenhuma modificação à configuração do sistema. O serviço permission_broker controla o acesso ao USB dispositivos e permitirá que o navegador os acesse, desde que haja pelo menos uma interface sem reivindicação.
Windows
O modelo de driver do Windows apresenta um requisito extra. Ao contrário do plataformas acima da capacidade de abrir um dispositivo USB a partir de um aplicativo do usuário o padrão, mesmo que não haja nenhum driver carregado. Em vez disso, há um WinUSB, que precisa ser carregado para fornecer a interface usam para acessar o dispositivo. Isso pode ser feito com um modelo arquivo de informações do driver (INF) instalado no sistema ou modificando o dispositivo firmware para fornecer os descritores de compatibilidade do SO Microsoft durante enumeração.
Arquivo de informações do motorista (INF)
Um arquivo de informações do driver informa ao Windows o que fazer ao encontrar um dispositivo
pela primeira vez. Como o sistema do usuário já inclui o driver WinUSB
basta que o arquivo INF associe o fornecedor e o ID do produto
com essa nova regra de instalação. O arquivo abaixo é um exemplo básico. Salve-o em um
com a extensão .inf
, mude as seções marcadas com "X" e depois
clique nele e escolha "Instalar" no menu de contexto.
[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"
A seção [Dev_AddReg]
configura o conjunto de DeviceInterfaceGUIDs para o
dispositivo. Cada interface de dispositivo deve ter um GUID para que um aplicativo
encontrá-lo e se conectar a ele pela API do Windows. Usar o PowerShell New-Guid
cmdlet ou uma ferramenta on-line para gerar um GUID aleatório.
Para fins de desenvolvimento, a ferramenta Zadig oferece uma interface fácil para para substituir o driver carregado de uma interface USB pelo WinUSB.
Descritores de compatibilidade do SO Microsoft
A abordagem de arquivo INF acima é trabalhosa porque exige a configuração de todos os a máquina do usuário com antecedência. O Windows 8.1 e as versões mais recentes com o uso de descritores USB personalizados. Esses descritores fornecem informações ao sistema operacional Windows quando o dispositivo é conectado pela primeira vez normalmente ser incluídas no arquivo INF.
Depois de configurar os descritores WebUSB, é fácil adicionar o sistema operacional da Microsoft
descritores de compatibilidade. Primeiro, estenda o descritor BOS com este
descritor de capacidade adicional da plataforma. Não se esqueça de atualizar o app wTotalLength
e bNumDeviceCaps
para considerar isso.
Valor | Campo | Descrição |
---|---|---|
Descritor de recursos da plataforma Microsoft OS 2.0 | ||
0x1C |
bLength | Tamanho deste descritor |
0x10 |
bDescriptorType | Descritor de capacidade do dispositivo |
0x05 |
bDevCapabilityType | Descritor de recursos da plataforma |
0x00 |
bReserved | |
{0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F} |
PlatformCapablityUUID | Descritor GUID de compatibilidade da plataforma Microsoft OS 2.0 no formato small-endian |
0x06030000 |
dwWindowsVersion | Versão mínima do Windows compatível (Windows 8.1) |
0x00B2 |
wMSOSDescriptorSetTotalLength | Tamanho total do conjunto do descritor |
0x02 |
bMS_VendorCode | Valor de bRequest para recuperar outros descritores da Microsoft |
0x00 |
bAltEnumCode | O dispositivo não é compatível com enumeração alternativa |
Assim como nos descritores WebUSB, você precisa escolher um valor bRequest
para ser usado pelo
e controla as transferências relacionadas a esses descritores. Neste exemplo, escolhi
0x02
: 0x07
, colocado em wIndex
, é o comando para recuperar o SO Microsoft
2.0 Conjunto do descritor do dispositivo.
bmRequestType | bRequest | wValue | wIndex | wLength | Dados (resposta) |
---|---|---|---|---|---|
0b11000000 |
0x02 |
0x0000 |
0x0007 |
* | Conjunto de descritor do MS OS 2.0 |
Um dispositivo USB pode ter várias funções e, portanto, a primeira parte do descritor
O conjunto descreve a qual função as propriedades a seguir estão associadas. A
abaixo configura a interface 1 de um dispositivo composto. O descritor fornece
duas informações importantes sobre essa interface. Os modelos
O descritor de ID informa ao Windows que este dispositivo é compatível com a rede WinUSB
motorista. O descritor de propriedade do registro funciona de forma semelhante à
Seção [Dev_AddReg]
do exemplo INF acima, definindo uma propriedade de registro como
atribua a essa função um GUID da interface do dispositivo.
Valor | Campo | Descrição |
---|---|---|
Cabeçalho do conjunto de descritor do Microsoft OS 2.0 | ||
0x000A |
wLength | Tamanho deste descritor |
0x0000 |
wDescriptorType | Descritor do cabeçalho do conjunto de descritor |
0x06030000 |
dwWindowsVersion | Versão mínima do Windows compatível (Windows 8.1) |
0x00B2 |
wTotalLength | Tamanho total do conjunto do descritor |
Cabeçalho do subconjunto de configuração do Microsoft OS 2.0 | ||
0x0008 |
wLength | Tamanho deste descritor |
0x0001 |
wDescriptorType | Descrição do cabeçalho do subconjunto de configuração |
0x00 |
bConfigurationValue | Aplica-se à configuração 1 (indexada de 0 apesar das configurações normalmente indexado a partir de 1) |
0x00 |
bReserved | Precisa ser definido como 0 |
0x00A8 |
wTotalLength | Tamanho total do subconjunto que inclui este cabeçalho |
Cabeçalho do subconjunto de funções do Microsoft OS 2.0 | ||
0x0008 |
wLength | Tamanho deste descritor |
0x0002 |
wDescriptorType | Descritor do cabeçalho do subconjunto de função |
0x01 |
bFirstInterface | Primeira interface da função |
0x00 |
bReserved | Precisa ser definido como 0 |
0x00A0 |
wSubsetLength | Tamanho total do subconjunto que inclui este cabeçalho |
Descritor de ID compatível com Microsoft OS 2.0 | ||
0x0014 |
wLength | Tamanho deste descritor |
0x0003 |
wDescriptorType | Descritor de ID compatível |
"WINUSB\0\0" |
CompatibileID | String ASCII preenchida com 8 bytes |
"\0\0\0\0\0\0\0\0" |
SubCompatibleID | String ASCII preenchida com 8 bytes |
Descritor de propriedade de registro do Microsoft OS 2.0 | ||
0x0084 |
wLength | Tamanho deste descritor |
0x0004 |
wDescriptorType | Descritor de propriedade de registro |
0x0007 |
wPropertyDataType | REG_MULTI_SZ |
0x002A |
wPropertyNameLength | Tamanho do nome da propriedade |
"DeviceInterfaceGUIDs\0" |
PropertyName | Nome da propriedade com terminador nulo codificado em UTF-16LE |
0x0050 |
wPropertyDataLength | Tamanho do valor da propriedade |
"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}\0\0" |
PropertyData | GUID mais dois terminadores nulos codificados em UTF-16LE |
O Windows só consulta o dispositivo uma vez para encontrar essas informações. Se o dispositivo não responder com descritores válidos, ele não perguntará novamente na próxima vez que o dispositivo está conectado. A Microsoft forneceu uma lista de registros de dispositivos USB Entradas que descrevem as entradas de registro criadas ao enumerar um dispositivo. Quando o teste exclui as entradas criadas para um dispositivo para forçar o Windows a tentar ler os descritores novamente.
Para mais informações, confira a postagem do blog da Microsoft sobre como usá-los descritores.
Exemplos
Exemplo de código que implementa dispositivos com reconhecimento de WebUSB que incluem WebUSB descritores do Microsoft OS e podem ser encontrados nestes projetos: