Dispositivi USB

Questo documento descrive come utilizzare l'API USB per comunicare con i dispositivi USB. Alcuni dispositivi non sono accessibili tramite l'API USB (per informazioni dettagliate, consulta la sezione Avvertenze di seguito). App di Chrome può anche connettersi a dispositivi serie e Bluetooth.

Per informazioni di base sull'USB, consulta le specifiche USB ufficiali. USB in a NutShell è un percorso anomalo che potrebbe esserti utile.

Requisito del file manifest

L'API USB richiede "usb" nel file manifest:

"permissions": [
  "usb"
]

Inoltre, per evitare impronte, devi dichiarare tutti i tipi di dispositivi che a cui vuoi accedere nel file manifest. Ogni tipo di dispositivo USB corrisponde a un ID fornitore/ID prodotto (VID/PID). Puoi utilizzare usb.getDevices per enumerare i dispositivi in base alla coppia VID/PID.

Devi dichiarare le coppie VID/PID per ogni tipo di dispositivo che vuoi utilizzare ai sensi della usbDevices nel file manifest dell'app, come mostrato nell'esempio seguente:

"permissions": [
  {
    "usbDevices": [
      {
        "vendorId": 123,
        "productId": 456
      }
    ]
  }
]

A partire da Chrome 57, il requisito per dichiarare tutti i tipi di dispositivi nel file manifest dell'app è per le app eseguite come app kiosk di ChromeOS. Per le app kiosk, puoi utilizzare interfaceClass proprietà di autorizzazione per richiedere l'autorizzazione ad accedere ai dispositivi USB che:

  • implementare un'interfaccia USB di una specifica classe di interfaccia
  • una specifica classe di dispositivi USB

Ad esempio, la seguente autorizzazione usbDevices concederà a un'app l'accesso a tutti i dispositivi USB che implementare un'interfaccia della stampante (codice classe di interfaccia 7) e ai dispositivi hub USB (codice classe dispositivo 9):

"permissions": [
  {
    "usbDevices": [
      {"interfaceClass": 7},
      {"interfaceClass": 9}
    ]
  }
]

Per l'elenco dei valori interfaceClass accettabili, vedi Codici di classe USB.

La proprietà interfaceClass può essere combinata con la proprietà vendorId per avere accesso solo a USB di dispositivi di un determinato fornitore, come illustrato nell'esempio seguente:

"permissions": [
  {
    "usbDevices": [
      {
        "vendorId": 123,
        "interfaceClass": 7
      }
    ]
  }
]

Ricerca di un dispositivo

Per determinare se uno o più dispositivi specifici sono connessi al sistema di un utente, utilizza la Metodo usb.getDevices:

chrome.usb.getDevices(enumerateDevicesOptions, callback);
Parametro (type)Descrizione
EnumerateDevicesOptions (oggetto)Un oggetto che specifica sia vendorId (long) sia productId (long) utilizzato per trovare il tipo corretto di dispositivo sul bus. Il file manifest deve dichiarare la sezione delle autorizzazioni usbDevices che elenca tutte le coppie vendorId e deviceId a cui l'app vuole accedere.
callback (funzione)Richiamato al termine dell'enumerazione del dispositivo. Il callback verrà eseguito con un parametro, un array di oggetti Device con tre proprietà: device, vendorId, productId. La proprietà del dispositivo è un identificatore stabile di un dispositivo connesso. e non cambierà finché il dispositivo non verrà scollegato dall'alimentazione. Il dettaglio dell'identificatore è opaco e soggetto a modifiche. Non fare affidamento sul tipo attuale.
Se non vengono trovati dispositivi, l'array sarà vuoto.

Esempio:

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);

Apertura di un dispositivo

Una volta restituiti gli oggetti Device, puoi aprire un dispositivo utilizzando usb.openDevice per ottenere un l'handle di connessione. Puoi comunicare con i dispositivi USB solo utilizzando gli handle di connessione.

ProprietàDescrizione
dispositivoOggetto ricevuto nel callback usb.getDevices.
dati (arraybuffer)Contiene i dati inviati dal dispositivo se il trasferimento è in entrata.

Esempio:

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);

Per semplificare la procedura di apertura, puoi usare il metodo usb.findDevices, che enumera, richiede l'accesso e apre i dispositivi in una chiamata:

chrome.usb.findDevices({"vendorId": vendorId, "productId": productId, "interfaceId": interfaceId}, callback);

che equivale 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);
        }
      });
    });
  })
});

Trasferimento e ricezione di dati da un dispositivo tramite USB

Il protocollo USB definisce quattro tipi di trasferimenti: di controllo, collettivi, icronologici e interrompere. Questi trasferimenti sono descritti di seguito.

I trasferimenti possono avvenire in entrambe le direzioni: da dispositivo a host (in entrata) e da host a dispositivo (in uscita). Scadenza a seconda della natura del protocollo USB, i messaggi in entrata e in uscita devono essere avviati dall'host (il computer su cui è installata l'app Chrome). Per i messaggi in entrata (da dispositivo a host), l'host (avviato dal tuo codice JavaScript) invia un messaggio contrassegnato come "in entrata" al dispositivo. I dettagli del dipendono dal dispositivo, ma generalmente sono presenti alcune informazioni identificative in merito alla richiesta da lì. Il dispositivo risponde quindi con i dati richiesti. La risposta del dispositivo viene gestita Chrome e pubblicato in modo asincrono in base al callback specificato nel metodo di trasferimento. Un server (host-to-device) è simile, ma la risposta non contiene dati restituiti dal dispositivo.

Per ogni messaggio dal dispositivo, il callback specificato riceverà un oggetto evento con il seguenti proprietà:

ProprietàDescrizione
resultCode (numero intero)0 indica una riuscita; altri valori indicano un errore. È possibile
leggere una stringa di errore da chrome.extension.lastError quando viene
indicato un errore.
dati (arraybuffer)Contiene i dati inviati dal dispositivo se il trasferimento è in entrata.

Esempio:

var onTransferCallback = function(event) {
   if (event && event.resultCode === 0 && event.data) {
     console.log("got " + event.data.byteLength + " bytes");
   }
};

chrome.usb.bulkTransfer(connectionHandle, transferInfo, onTransferCallback);

CONTROLLA trasferimenti

I trasferimenti di controllo vengono generalmente utilizzati per inviare o ricevere parametri di configurazione o di comando a un dispositivo USB dispositivo. Il metodo controlTransfer invia sempre/legge dall'endpoint 0 e non è presente claimInterface obbligatorio. Il metodo è semplice e riceve tre parametri:

chrome.usb.controlTransfer(connectionHandle, transferInfo, transferCallback)
Parametro (tipi)Descrizione
connectionHandleOggetto ricevuto nel callback usb.openDevice.
transferInfoOggetto parametro con valori riportati nella tabella seguente. Per informazioni dettagliate, controlla le specifiche del protocollo del dispositivo USB.
transferCallback()Richiamato quando il trasferimento è stato completato.

Valori per l'oggetto transferInfo:

ValoreDescrizione
requestType (stringa)"vendor", "standard", "class" o "prenotato".
destinatario (stringa)"device", "interface", "endpoint" o "altro".
direzione (stringa)"in" o "fuori". La viene utilizzata per comunicare al dispositivo che
deve inviare informazioni all'host. Tutte le comunicazioni su un bus
USB sono avviate dall'host, quindi usa un "in" trasferire le informazioni per consentire a un dispositivo
di restituirti informazioni.
richiesta (numero intero)Definite dal protocollo del tuo dispositivo.
valore (intero)Definite dal protocollo del tuo dispositivo.
indice (numero intero)Definite dal protocollo del tuo dispositivo.
lunghezza (numero intero)Utilizzato solo quando la direzione è "in". Informa il dispositivo che si tratta della quantità di dati che l'host si aspetta in risposta.
dati (arraybuffer)Definito dal protocollo del dispositivo, richiesto quando la direzione è "out".

Esempio:

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);

Trasferimenti ISOCRONO

I trasferimenti sincrono sono il tipo più complesso di trasferimento USB. Sono comunemente utilizzati per gli stream di dati, come video e audio. Per avviare un trasferimento sincronizzato (in entrata o in uscita), devi utilizzare il metodo usb.isochronousTransfer:

chrome.usb.isochronousTransfer(connectionHandle, isochronousTransferInfo, transferCallback)
ParametroDescrizione
connectionHandleOggetto ricevuto nel callback usb.openDevice.
isochronousTransferInfoOggetto parametro con i valori riportati nella seguente tabella.
transferCallback()Richiamato quando il trasferimento è stato completato.

Valori per l'oggetto isochronousTransferInfo:

ValoreDescrizione
transferInfo (oggetto)Un oggetto con i seguenti attributi:
direction (string): "in" o "out".
endpoint (numero intero): definito dal tuo dispositivo. In genere puoi trovarlo osservando uno strumento di ispezione USB, ad esempio lsusb -v
length (integer): utilizzato solo quando la direzione è "in". Informa il dispositivo che si tratta della quantità di dati che l'host si aspetta in risposta.
Deve essere ALMENO packets × packetLength.
dati (arraybuffer): definiti dal protocollo del dispositivo; utilizzata solo quando la direzione è "out".
pacchetti (numero intero)Numero totale di pacchetti previsti in questo trasferimento.
packageLength (numero intero)Lunghezza prevista di ogni pacchetto in questo trasferimento.

Esempio:

var transferInfo = {
  "direction": "in",
  "endpoint": 1,
  "length": 2560
};

var isoTransferInfo = {
  "transferInfo": transferInfo,
  "packets": 20,
  "packetLength": 128
};

chrome.usb.isochronousTransfer(connectionHandle, isoTransferInfo, optionalCallback);

Trasferimenti MASSIMO

I trasferimenti collettivi sono comunemente utilizzati per trasferire una grande quantità di dati non urgenti in modo affidabile in molti modi diversi. usb.bulkTransfer ha tre parametri:

chrome.usb.bulkTransfer(connectionHandle, transferInfo, transferCallback);
ParametroDescrizione
connectionHandleOggetto ricevuto nel callback usb.openDevice.
transferInfoOggetto parametro con i valori riportati nella seguente tabella.
transferCallbackRichiamato quando il trasferimento è stato completato.

Valori per l'oggetto transferInfo:

ValoreDescrizione
direzione (stringa)"in" o "fuori".
endpoint (numero intero)Definite dal protocollo del tuo dispositivo.
lunghezza (numero intero)Utilizzato solo quando la direzione è "in". Informa il dispositivo che si tratta della quantità di dati che l'host si aspetta in risposta.
dati (ArrayBuffer)Definite dal protocollo del tuo dispositivo. utilizzata solo quando la direzione è "out".

Esempio:

var transferInfo = {
  "direction": "out",
  "endpoint": 1,
  "data": new Uint8Array([4, 8, 15, 16, 23, 42]).buffer
};

Trasferimenti INTERRUPT

I trasferimenti di interruzione sono utilizzati su una quantità ridotta di dati sensibili al tempo. Dato che tutte le comunicazioni USB sono avviato dall'host, il codice host di solito esegue il polling del dispositivo periodicamente, inviando interrupt IN trasferimenti che consentono al dispositivo di restituire i dati se c'è qualcosa nella coda di interruzioni. (gestito dal dispositivo). usb.interruptTransfer ha tre parametri:

chrome.usb.interruptTransfer(connectionHandle, transferInfo, transferCallback);
ParametroDescrizione
connectionHandleOggetto ricevuto nel callback usb.openDevice.
transferInfoOggetto parametro con i valori riportati nella seguente tabella.
transferCallbackRichiamato quando il trasferimento è stato completato. Tieni presente che questo callback non contiene la risposta del dispositivo. Lo scopo del callback è notificare al tuo codice che le richieste di trasferimento asincrone sono state elaborate.

Valori per l'oggetto transferInfo:

ValoreDescrizione
direzione (stringa)"in" o "fuori".
endpoint (numero intero)Definite dal protocollo del tuo dispositivo.
lunghezza (numero intero)Utilizzato solo quando la direzione è "in". Informa il dispositivo che si tratta della quantità di dati che l'host si aspetta in risposta.
dati (ArrayBuffer)Definite dal protocollo del tuo dispositivo. utilizzata solo quando la direzione è "out".

Esempio:

var transferInfo = {
  "direction": "in",
  "endpoint": 1,
  "length": 2
};
chrome.usb.interruptTransfer(connectionHandle, transferInfo, optionalCallback);

Avvertenze

Non tutti i dispositivi sono accessibili tramite l'API USB. In generale, i dispositivi non sono accessibili il kernel del sistema operativo o un driver nativo li trattiene dal codice dello spazio utente. Alcune esempi di dispositivi con profili HID su sistemi OSX e pen drive USB.

Sulla maggior parte dei sistemi Linux, i dispositivi USB sono mappati con autorizzazioni di sola lettura per impostazione predefinita. Per aprire un dispositivo tramite questa API, l'utente dovrà disporre anche dell'accesso in scrittura all'API. Una soluzione semplice è imposta una regola udev. Crea un file /etc/udev/rules.d/50-yourdevicename.rules con quanto segue contenuti:

SUBSYSTEM=="usb", ATTR{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"

Quindi, riavvia il daemon udev: service udev restart. Puoi controllare se le autorizzazioni del dispositivo sono correttamente procedendo nel seguente modo:

  • Esegui lsusb per trovare i numeri del bus e dei dispositivi.
  • Esegui ls -al /dev/bus/usb/[bus]/[device]. Questo file deve essere di proprietà del gruppo "plugdev" e hanno autorizzazioni di scrittura del gruppo.

L'app non può eseguire questa operazione automaticamente poiché questa procedura richiede l'accesso root. I nostri suggerimenti fornire istruzioni agli utenti finali e inserire un link alla sezione Avvertenze in questa pagina per spiegazione.

Su ChromeOS, basta chiamare usb.requestAccess. Il broker di autorizzazioni se ne occupa per te.