Périphériques USB

Ce document explique comment utiliser l'API USB pour communiquer avec des appareils USB. Certains appareils ne sont pas accessibles via l'API USB (pour en savoir plus, consultez la section Mises en garde ci-dessous). Applications Chrome peuvent également se connecter aux appareils serial et Bluetooth.

Pour obtenir des informations générales sur la connexion USB, consultez les spécifications USB officielles. Le cours d'initiation USB in a NutShell est raisonnable et peut vous être utile.

Exigence du fichier manifeste

L'API USB nécessite la clé "usb" dans le fichier manifeste:

"permissions": [
  "usb"
]

En outre, afin d'éviter l'impression d'empreinte digitale, vous devez déclarer tous les types d'appareils que vous auquel vous souhaitez accéder dans le fichier manifeste. Chaque type de périphérique USB correspond à un identifiant de fournisseur/produit. (VID/PID). Vous pouvez utiliser usb.getDevices pour énumérer les appareils en fonction de leur paire VID/PID.

Vous devez déclarer les paires VID/PID pour chaque type d'appareil que vous souhaitez utiliser dans le usbDevices dans le fichier manifeste de votre application, comme illustré dans l'exemple ci-dessous:

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

Depuis Chrome 57, la déclaration de tous les types d'appareils dans le fichier manifeste de l'application est obligatoire pour les applications exécutées en tant que kiosques ChromeOS. Pour les applications kiosque, vous pouvez utiliser les Propriété d'autorisation interfaceClass pour demander l'autorisation d'accéder aux appareils USB qui:

  • implémenter une interface USB d'une classe d'interface spécifique
  • ont une classe de périphérique USB spécifique

Par exemple, l'autorisation usbDevices suivante accorderait à une application l'accès à tous les appareils USB qui Implémentez une interface d'imprimante (code de classe d'interface 7) et des périphériques USB (code de classe de périphérique). 9):

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

Pour obtenir la liste des valeurs interfaceClass acceptées, consultez les codes de classe USB.

La propriété interfaceClass peut être combinée à la propriété vendorId pour n'accéder qu'aux clés USB appareils d'un fournisseur spécifique, comme illustré dans l'exemple suivant:

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

Trouver un appareil

Pour déterminer si un ou plusieurs appareils spécifiques sont connectés au système d'un utilisateur, utilisez le usb.getDevices:

chrome.usb.getDevices(enumerateDevicesOptions, callback);
Paramètre (type)Description
EnumerateDevicesOptions (objet)Objet spécifiant à la fois un vendorId (long) et un productId (long) utilisé pour trouver le type d'appareil approprié dans le bus. Votre fichier manifeste doit déclarer la section d'autorisations usbDevices qui répertorie toutes les associations vendorId et deviceId auxquelles votre application souhaite accéder.
rappel (fonction)Appelé lorsque l'énumération de l'appareil est terminée. Le rappel sera exécuté avec un paramètre, à savoir un tableau d'objets Device avec trois propriétés: device, vendorId et productId. La propriété de l'appareil est un identifiant stable pour un appareil connecté. Cela ne changera qu'une fois l'appareil débranché. Les détails de l'identifiant sont opaques et susceptibles d'être modifiés. Ne vous fiez pas à son type actuel.
Si aucun appareil n'est détecté, le réseau sera vide.

Exemple :

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

Ouverture d'un appareil

Une fois les objets Device renvoyés, vous pouvez ouvrir un appareil à l'aide de usb.openDevice pour obtenir un de connexion. Vous ne pouvez communiquer avec des appareils USB qu'à l'aide de poignées de connexion.

PropriétéDescription
appareilObjet reçu dans le rappel usb.getDevices
données (arraybuffer)Contient les données envoyées par l'appareil si le transfert était entrant.

Exemple :

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

Pour simplifier le processus d'ouverture, vous pouvez utiliser la méthode usb.findDevices, qui énumère : demande l'accès et ouvre les appareils en un seul appel:

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

ce qui équivaut à:

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

Transferts USB et réception de données depuis un appareil

Le protocole USB définit quatre types de transferts: de contrôle, en masse, isochronous et l'interruption. Ces transferts sont décrits ci-dessous.

Les transferts peuvent se produire dans les deux sens: d'appareil à hôte (entrant) et d'hôte à appareil (sortant). Date limite à la nature du protocole USB, les messages entrants et sortants doivent être initiés par l'hôte (l'ordinateur qui exécute l'application Chrome). Pour les messages entrants (de l'appareil à l'hôte), l'hôte (initié) par votre code JavaScript) envoie un message marqué comme "entrant" à l'appareil. Les détails dépendent de l'appareil, mais il permet généralement d'identifier l'objet de votre demande. à partir de celui-ci. L'appareil répond alors en fournissant les données demandées. La réponse de l'appareil est gérée par Chrome et envoyé de manière asynchrone au rappel que vous spécifiez dans la méthode de transfert. Un appel sortant (host-to-device) est similaire, mais la réponse ne contient pas les données renvoyées par l'appareil.

Pour chaque message provenant de l'appareil, le rappel spécifié recevra un objet d'événement avec le paramètre les propriétés suivantes:

PropriétéDescription
resultCode (entier)0 correspond au succès ; d'autres valeurs indiquent un échec. Une chaîne d'erreur peut être
lue à partir de chrome.extension.lastError lorsqu'un échec est
indiqué.
données (arraybuffer)Contient les données envoyées par l'appareil si le transfert était entrant.

Exemple :

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

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

CONTROL transferts

Les transferts de contrôle sont généralement utilisés pour envoyer ou recevoir des paramètres de configuration ou de commande vers une clé USB appareil. La méthode "controlTransfer" envoie toujours vers/lit le point de terminaison 0, et aucune claimInterface n'est obligatoire. La méthode est simple et reçoit trois paramètres:

chrome.usb.controlTransfer(connectionHandle, transferInfo, transferCallback)
Paramètre (types)Description
connectionHandleObjet reçu dans le rappel usb.openDevice.
transferInfoObjet de paramètre avec les valeurs du tableau ci-dessous. Pour en savoir plus, consultez les spécifications du protocole USB.
transferCallback()Invoqué une fois le transfert terminé.

Valeurs de l'objet transferInfo:

ValeurDescription
requestType (chaîne)"vendor", "standard", "class" ou "réservées".
destinataire (chaîne)"appareil", "interface", "point de terminaison" ou "autre".
direction (chaîne)"dans" ou "out". Le "dans" la direction indique à l'appareil
qu'il doit envoyer des informations à l'hôte. Toutes les communications sur un bus USB
sont initiées par l'hôte. Utilisez donc un point d'entrée pour permettre à un appareil
de renvoyer des informations.
requête (entier)Définie par le protocole de votre appareil.
valeur (entier)Définie par le protocole de votre appareil.
index (entier)Définie par le protocole de votre appareil.
longueur (entier)Utilisé uniquement lorsque la direction est "dans". Informe l'appareil qu'il s'agit de la quantité de données attendue par l'hôte en réponse.
données (arraybuffer)Définie par le protocole de votre appareil, obligatoire lorsque la direction est "sortante".

Exemple :

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

Transferts ISOCHRONOUS

Les transferts isochrones sont le type de transfert USB le plus complexe. Ils sont couramment utilisés pour les flux de données, comme les vidéos et le son. Pour lancer un transfert isochrone (entrant ou sortant), vous devez devez utiliser la méthode usb.isochronousTransfer:

chrome.usb.isochronousTransfer(connectionHandle, isochronousTransferInfo, transferCallback)
ParamètreDescription
connectionHandleObjet reçu dans le rappel usb.openDevice.
isochronousTransferInfoParamètre avec les valeurs du tableau ci-dessous.
transferCallback()Invoqué une fois le transfert terminé.

Valeurs de l'objet isochronousTransferInfo:

ValeurDescription
TransferInfo (objet)Un objet avec les attributs suivants:
direction (string): "in" ou "out".
point de terminaison (entier) : défini par votre appareil. Ils se trouvent généralement à l'aide d'un outil d'introspection USB, comme lsusb -v
length (integer) (longueur (entier)): utilisé uniquement lorsque la direction est "in". Informe l'appareil qu'il s'agit de la quantité de données attendues par l'hôte en réponse.
La valeur doit être AU MOINS packets × packetLength.
données (tampon de tableau) : définies par le protocole de votre appareil. utilisé uniquement lorsque la direction est "vers l'extérieur".
paquets (entier)Nombre total de paquets attendus dans ce transfert.
speechLength (entier)Longueur attendue de chaque paquet dans ce transfert.

Exemple :

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

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

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

Transferts groupés

Les transferts groupés sont généralement utilisés pour transférer une grande quantité de données non urgentes de la même façon. usb.bulkTransfer comporte trois paramètres:

chrome.usb.bulkTransfer(connectionHandle, transferInfo, transferCallback);
ParamètreDescription
connectionHandleObjet reçu dans le rappel usb.openDevice.
transferInfoParamètre avec les valeurs du tableau ci-dessous.
transferCallbackInvoqué une fois le transfert terminé.

Valeurs de l'objet transferInfo:

ValeurDescription
direction (chaîne)"dans" ou "out".
point de terminaison (entier)Définie par le protocole de votre appareil.
longueur (entier)Utilisé uniquement lorsque la direction est "dans". Informe l'appareil qu'il s'agit de la quantité de données attendue par l'hôte en réponse.
données (ArrayBuffer)défini par le protocole de votre appareil ; utilisé uniquement lorsque la direction est "vers l'extérieur".

Exemple :

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

INTERRUPT de transferts

Les transferts d'interruption sont utilisés pour une petite quantité de données sensibles dans le temps. Étant donné que toutes les communications USB sont initiée par l'hôte, le code de l'hôte interroge généralement l'appareil régulièrement, envoyant une interruption dans Les transferts qui permettront à l'appareil de renvoyer des données en cas de file d'attente d'interruptions (gérée par l'appareil). usb.interruptTransfer comporte trois paramètres:

chrome.usb.interruptTransfer(connectionHandle, transferInfo, transferCallback);
ParamètreDescription
connectionHandleObjet reçu dans le rappel usb.openDevice.
transferInfoParamètre avec les valeurs du tableau ci-dessous.
transferCallbackInvoqué une fois le transfert terminé. Notez que ce rappel ne contient pas la réponse de l'appareil. Le rappel a simplement pour but d'informer votre code que les demandes de transfert asynchrones ont été traitées.

Valeurs de l'objet transferInfo:

ValeurDescription
direction (chaîne)"dans" ou "out".
point de terminaison (entier)Définie par le protocole de votre appareil.
longueur (entier)Utilisé uniquement lorsque la direction est "dans". Informe l'appareil qu'il s'agit de la quantité de données attendue par l'hôte en réponse.
données (ArrayBuffer)défini par le protocole de votre appareil ; utilisé uniquement lorsque la direction est "vers l'extérieur".

Exemple :

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

Mises en garde

Tous les appareils ne sont pas accessibles via l'API USB. En général, les appareils ne sont pas accessibles car le noyau du système d’exploitation ou un pilote natif les empêche du code de l’espace utilisateur. Un peu exemples sont les appareils avec des profils HID sur les systèmes OSX et les clés USB.

Sur la plupart des systèmes Linux, les périphériques USB sont mappés avec des autorisations de lecture seule par défaut. Pour ouvrir un appareil via cette API, l'utilisateur devra également y avoir accès en écriture. Une solution simple consiste à définir une règle udev. Créez un fichier /etc/udev/rules.d/50-yourdevicename.rules avec les éléments suivants : contenu:

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

Il vous suffit ensuite de redémarrer le daemon udev: service udev restart. Vous pouvez vérifier si les autorisations de l'appareil correctement définie. Pour ce faire, procédez comme suit:

  • Exécutez lsusb pour trouver les numéros de bus et d'appareil.
  • Exécutez ls -al /dev/bus/usb/[bus]/[device]. Ce fichier doit appartenir au groupe "plugdev". et vous avez autorisations d'écriture de groupe.

Votre application ne peut pas le faire automatiquement, car cette procédure nécessite un accès root. Nous vous recommandons fournissez des instructions aux utilisateurs finaux et fournissez un lien vers la section Mises en garde de cette page pour obtenir explicative.

Sous ChromeOS, il vous suffit d'appeler usb.requestAccess. L'agent d'autorisations effectue cette opération à votre place.