Este documento descreve como usar a API USB para se comunicar com dispositivos USB. Alguns dispositivos não podem ser acessados pela API USB. Consulte a seção Observações abaixo para mais detalhes. Esses apps também podem se conectar a dispositivos serial e Bluetooth.
Para informações contextuais sobre o USB, consulte as especificações USB oficiais. USB em um NutShell é um curso intensivo razoável que pode ser útil.
Requisito do manifesto
A API USB requer a permissão "usb" no arquivo de manifesto:
"permissions": [
"usb"
]
Além disso, para evitar a impressão digital, é necessário declarar todos os tipos de dispositivo que você quer acessar no arquivo de manifesto. Cada tipo de dispositivo USB corresponde a um par de ID de fornecedor/ID do produto (VID/PID, na sigla em inglês). Você pode usar usb.getDevices para enumerar dispositivos pelo par de VID/PID.
Declare os pares de VID/PID para cada tipo de dispositivo que você quer usar com a permissão usbDevices
no arquivo de manifesto do app, conforme mostrado no exemplo abaixo:
"permissions": [
{
"usbDevices": [
{
"vendorId": 123,
"productId": 456
}
]
}
]
Desde o Chrome 57, o requisito de declarar todos os tipos de dispositivos no manifesto do app foi
relaxado para apps em execução como aplicativos de quiosque do ChromeOS. Para aplicativos de quiosque, use a
propriedade de permissão interfaceClass
para solicitar acesso a dispositivos USB que:
- implementar uma interface USB de uma classe de interface específica
- tiver uma classe específica de dispositivo USB;
Por exemplo, a permissão usbDevices
abaixo concederia ao app acesso a todos os dispositivos USB que
implementam uma interface de impressora (código de classe de interface 7) e a dispositivos de hub USB (código de classe de dispositivo
9):
"permissions": [
{
"usbDevices": [
{"interfaceClass": 7},
{"interfaceClass": 9}
]
}
]
Para ver a lista de valores de interfaceClass
aceitáveis, consulte Códigos de classe USB.
A propriedade interfaceClass
pode ser combinada com a propriedade vendorId
para ter acesso apenas a dispositivos
USB de um fornecedor específico, conforme demonstrado no exemplo a seguir:
"permissions": [
{
"usbDevices": [
{
"vendorId": 123,
"interfaceClass": 7
}
]
}
]
Como encontrar um dispositivo
Para determinar se um ou mais dispositivos específicos estão conectados ao sistema de um usuário, use o método usb.getDevices:
chrome.usb.getDevices(enumerateDevicesOptions, callback);
Parâmetro (tipo) | Descrição |
---|---|
EnumerateDevicesOptions (objeto) | Um objeto que especifica um vendorId (longo) e productId (longo) usado para encontrar o tipo correto de dispositivo no ônibus. Seu manifesto precisa declarar a seção de permissões usbDevices , que lista todos os pares vendorId e deviceId que o app quer acessar. |
callback (função) | Chamado quando a enumeração do dispositivo é concluída. O callback será executado com um parâmetro, uma matriz de objetos Device com três propriedades: device , vendorId , productId . A propriedade do dispositivo é um identificador estável para um dispositivo conectado. Ele não mudará até que o dispositivo seja desconectado. Os detalhes do identificador são opacos e estão sujeitos a mudanças. Não dependa do tipo atual.Se nenhum dispositivo for encontrado, a matriz estará vazia. |
Exemplos
function onDeviceFound(devices) {
this.devices=devices;
if (devices) {
if (devices.length > 0) {
console.log("Device(s) found: "+devices.length);
} else {
console.log("Device could not be found");
}
} else {
console.log("Permission denied.");
}
}
chrome.usb.getDevices({"vendorId": vendorId, "productId": productId}, onDeviceFound);
Abrindo um dispositivo
Depois que os objetos Device
forem retornados, será possível abrir um dispositivo usando usb.openDevice para receber um
identificador de conexão. Só é possível se comunicar com dispositivos USB usando alças de conexão.
Propriedade | Descrição |
---|---|
dispositivo | Objeto recebido no callback usb.getDevices. |
dados (arraybuffer) | Contém os dados enviados pelo dispositivo se a transferência foi de entrada. |
Exemplos
var usbConnection = null;
var onOpenCallback = function(connection) {
if (connection) {
usbConnection = connection;
console.log("Device opened.");
} else {
console.log("Device failed to open.");
}
};
chrome.usb.openDevice(device, onOpenCallback);
Para simplificar o processo de abertura, use o método usb.findDevices, que enumera, solicita acesso e abre dispositivos em uma única chamada:
chrome.usb.findDevices({"vendorId": vendorId, "productId": productId, "interfaceId": interfaceId}, callback);
o que é equivalente a:
chrome.usb.getDevices({"vendorId": vendorId, "productId": productId}, function (devices) {
if (!devices) {
console.log("Error enumerating devices.");
callback();
return;
}
var connections = [], pendingAccessRequests = devices.length;
devices.forEach(function (device) {
chrome.usb.requestAccess(interfaceId, function () {
// No need to check for errors at this point.
// Nothing can be done if an error occurs anyway. You should always try
// to open the device.
chrome.usb.openDevices(device, function (connection) {
if (connection) connections.push(connection);
pendingAccessRequests--;
if (pendingAccessRequests == 0) {
callback(connections);
}
});
});
})
});
Transferências e recebimento de dados por USB de um dispositivo
O protocolo USB define quatro tipos de transferências: controle, em massa, isocrono e interrupção. Essas baldeações são descritas abaixo.
As transferências podem ocorrer em ambas as direções: dispositivo para host (entrada) e host para dispositivo (saída). Devido à natureza do protocolo USB, as mensagens de entrada e saída precisam ser iniciadas pelo host (o computador que executa o app Chrome). Para mensagens recebidas (do dispositivo para o host), o host (iniciado pelo código JavaScript) envia uma mensagem sinalizada como "recebida" para o dispositivo. Os detalhes da mensagem dependem do dispositivo, mas geralmente trazem alguma identificação do que você está solicitando dele. Em seguida, o dispositivo responde com os dados solicitados. A resposta do dispositivo é processada pelo Chrome e entregue de forma assíncrona ao callback especificado no método de transferência. Uma mensagem de saída (do host para o dispositivo) é semelhante, mas a resposta não contém os dados retornados do dispositivo.
Para cada mensagem do dispositivo, o callback especificado receberá um objeto de evento com as seguintes propriedades:
Propriedade | Descrição |
---|---|
resultCode (número inteiro) | O valor 0 indica sucesso. Outros valores indicam falha. Uma string de erro pode ser lida em chrome.extension.lastError quando uma falha éindicada. |
dados (arraybuffer) | Contém os dados enviados pelo dispositivo se a transferência foi de entrada. |
Exemplos
var onTransferCallback = function(event) {
if (event && event.resultCode === 0 && event.data) {
console.log("got " + event.data.byteLength + " bytes");
}
};
chrome.usb.bulkTransfer(connectionHandle, transferInfo, onTransferCallback);
CONTROLAR baldeações
As transferências de controle geralmente são usadas para enviar ou receber parâmetros de configuração ou comando para um dispositivo USB. O método controlTransfer sempre envia/faz leituras no endpoint 0, e nenhuma claimInterface é necessária. O método é simples e recebe três parâmetros:
chrome.usb.controlTransfer(connectionHandle, transferInfo, transferCallback)
Parâmetro (tipos) | Descrição |
---|---|
connectionHandle | Objeto recebido no callback de usb.openDevice. |
transferInfo | Objeto de parâmetro com valores da tabela abaixo. Verifique a especificação do protocolo do dispositivo USB para mais detalhes. |
transferCallback() | Invocado quando a transferência é concluída. |
Valores do objeto transferInfo
:
Valor | Descrição |
---|---|
requestType (string) | "vendor", "standard", "class" ou "reservado". |
destinatário (string) | "device", "interface", "endpoint" ou "other". |
direção (string) | "entrar" ou "fora". A direção "de" é usada para notificar o dispositivo de que ele precisa enviar informações para o host. Toda a comunicação em um barramento USB é iniciada pelo host. Portanto, use uma transferência "em" para permitir que um dispositivo envie informações de volta. |
solicitação (número inteiro) | Definida pelo protocolo do dispositivo. |
valor (número inteiro) | Definida pelo protocolo do dispositivo. |
índice (número inteiro) | Definida pelo protocolo do dispositivo. |
tamanho (número inteiro) | Usado somente quando a direção é "para". Notifica o dispositivo de que essa é a quantidade de dados que o host espera em resposta. |
dados (arraybuffer) | Definida pelo protocolo do dispositivo, obrigatória quando a direção é "fora". |
Exemplos
var transferInfo = {
"requestType": "vendor",
"recipient": "device",
"direction": "out",
"request": 0x31,
"value": 120,
"index": 0,
// Note that the ArrayBuffer, not the TypedArray itself is used.
"data": new Uint8Array([4, 8, 15, 16, 23, 42]).buffer
};
chrome.usb.controlTransfer(connectionHandle, transferInfo, optionalCallback);
Transferências ISONOS
As transferências isócronas são o tipo mais complexo de transferência USB. Eles são comumente usados para streams de dados, como vídeo e som. Para iniciar uma transferência isócrona (de entrada ou saída), use o método usb.isochronousTransfer:
chrome.usb.isochronousTransfer(connectionHandle, isochronousTransferInfo, transferCallback)
Parâmetro | Descrição |
---|---|
connectionHandle | Objeto recebido no callback de usb.openDevice. |
isochronousTransferInfo | Objeto de parâmetro com os valores da tabela abaixo. |
transferCallback() | Invocado quando a transferência é concluída. |
Valores do objeto isochronousTransferInfo
:
Valor | Descrição |
---|---|
transferInfo (objeto) | Um objeto com os seguintes atributos: direction (string): "para dentro" ou "para fora". endpoint (número inteiro): definido pelo dispositivo. Geralmente, pode ser encontrado em uma ferramenta de inspeção USB, como lsusb -v comprimento (número inteiro): usado somente quando a direção é "in". Notifica o dispositivo de que essa é a quantidade de dados que o host está esperando em resposta. Precisa ser PELO MENOS packets × packetLength .dados (arraybuffer): definidos pelo protocolo do dispositivo. Usado somente quando a direção é "fora". |
pacotes (número inteiro) | Número total de pacotes esperados nesta transferência. |
packageLength (número inteiro) | Comprimento esperado de cada pacote nesta transferência. |
Exemplos
var transferInfo = {
"direction": "in",
"endpoint": 1,
"length": 2560
};
var isoTransferInfo = {
"transferInfo": transferInfo,
"packets": 20,
"packetLength": 128
};
chrome.usb.isochronousTransfer(connectionHandle, isoTransferInfo, optionalCallback);
Transferências em MASSA
As transferências em massa são normalmente usadas para transferir uma grande quantidade de dados não sensíveis ao tempo de maneira confiável. usb.bulkTransfer tem três parâmetros:
chrome.usb.bulkTransfer(connectionHandle, transferInfo, transferCallback);
Parâmetro | Descrição |
---|---|
connectionHandle | Objeto recebido no callback de usb.openDevice. |
transferInfo | Objeto de parâmetro com os valores da tabela abaixo. |
transferCallback | Invocado quando a transferência é concluída. |
Valores do objeto transferInfo
:
Valor | Descrição |
---|---|
direção (string) | "entrar" ou "fora". |
endpoint (número inteiro) | Definida pelo protocolo do dispositivo. |
tamanho (número inteiro) | Usado somente quando a direção é "para". Notifica o dispositivo de que essa é a quantidade de dados que o host espera em resposta. |
dados (ArrayBuffer) | Definida pelo protocolo do dispositivo, usada apenas quando a direção é "fora". |
Exemplos
var transferInfo = {
"direction": "out",
"endpoint": 1,
"data": new Uint8Array([4, 8, 15, 16, 23, 42]).buffer
};
INTERRUPTAR baldeações
As transferências de interrupção são usadas para uma pequena quantidade de dados sensíveis. Como toda a comunicação USB é iniciada pelo host, o código do host geralmente pesquisa o dispositivo periodicamente, enviando transferências IN de interrupção que farão o dispositivo enviar dados de volta se houver algo na fila de interrupção (mantida pelo dispositivo). O usb.interruptTransfer tem três parâmetros:
chrome.usb.interruptTransfer(connectionHandle, transferInfo, transferCallback);
Parâmetro | Descrição |
---|---|
connectionHandle | Objeto recebido no callback de usb.openDevice. |
transferInfo | Objeto de parâmetro com os valores da tabela abaixo. |
transferCallback | Invocado quando a transferência é concluída. Esse callback não contém a resposta do dispositivo. O propósito do callback é simplesmente notificar seu código de que as solicitações de transferência assíncronas foram processadas. |
Valores do objeto transferInfo
:
Valor | Descrição |
---|---|
direção (string) | "entrar" ou "fora". |
endpoint (número inteiro) | Definida pelo protocolo do dispositivo. |
tamanho (número inteiro) | Usado somente quando a direção é "para". Notifica o dispositivo de que essa é a quantidade de dados que o host espera em resposta. |
dados (ArrayBuffer) | Definida pelo protocolo do dispositivo, usada apenas quando a direção é "fora". |
Exemplos
var transferInfo = {
"direction": "in",
"endpoint": 1,
"length": 2
};
chrome.usb.interruptTransfer(connectionHandle, transferInfo, optionalCallback);
Avisos
Nem todos os dispositivos podem ser acessados pela API USB. Em geral, os dispositivos não podem ser acessados porque o kernel do sistema operacional ou um driver nativo os impede do código do espaço do usuário. Alguns exemplos são dispositivos com perfis HID em sistemas OSX e pen drives USB.
Na maioria dos sistemas Linux, os dispositivos USB são mapeados com permissões somente leitura por padrão. Para abrir um
dispositivo usando essa API, o usuário também precisará ter acesso de gravação a ele. Uma solução simples é definir
uma regra udev. Crie um arquivo /etc/udev/rules.d/50-yourdevicename.rules
com o seguinte
conteúdo:
SUBSYSTEM=="usb", ATTR{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"
Em seguida, reinicie o daemon udev: service udev restart
. É possível verificar se as permissões do dispositivo foram
definidas corretamente seguindo estas etapas:
- Execute
lsusb
para encontrar os números de ônibus e dispositivo. - Execute
ls -al /dev/bus/usb/[bus]/[device]
. Esse arquivo precisa pertencer ao grupo "plugdev" e ter permissões de gravação em grupo.
O app não pode fazer isso automaticamente porque o procedimento exige acesso à raiz. Recomendamos que você forneça instruções aos usuários finais e inclua um link para a seção Ressalvas desta página para uma explicação.
No ChromeOS, basta chamar usb.requestAccess. O agente de permissões faz isso para você.