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 |
---|---|
appareil | Objet 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 estindiqué. |
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 |
---|---|
connectionHandle | Objet reçu dans le rappel usb.openDevice. |
transferInfo | Objet 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
:
Valeur | Description |
---|---|
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ètre | Description |
---|---|
connectionHandle | Objet reçu dans le rappel usb.openDevice. |
isochronousTransferInfo | Paramètre avec les valeurs du tableau ci-dessous. |
transferCallback() | Invoqué une fois le transfert terminé. |
Valeurs de l'objet isochronousTransferInfo
:
Valeur | Description |
---|---|
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ètre | Description |
---|---|
connectionHandle | Objet reçu dans le rappel usb.openDevice. |
transferInfo | Paramètre avec les valeurs du tableau ci-dessous. |
transferCallback | Invoqué une fois le transfert terminé. |
Valeurs de l'objet transferInfo
:
Valeur | Description |
---|---|
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ètre | Description |
---|---|
connectionHandle | Objet reçu dans le rappel usb.openDevice. |
transferInfo | Paramètre avec les valeurs du tableau ci-dessous. |
transferCallback | Invoqué 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
:
Valeur | Description |
---|---|
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.