USB-Geräte

In diesem Dokument wird beschrieben, wie die USB API für die Kommunikation mit USB-Geräten verwendet wird. Einige Geräte sind über die USB API nicht zugänglich. Weitere Informationen finden Sie unten im Abschnitt Einschränkungen. Chrome-Apps können auch mit serial und Bluetooth-Geräten verbunden werden.

Hintergrundinformationen zu USB finden Sie in den offiziellen USB-Spezifikationen. USB in a NutShell ist ein guter Absturzkurs, der hilfreich sein könnte.

Manifestanforderung

Die USB API erfordert die Berechtigung „usb“ in der Manifestdatei:

"permissions": [
  "usb"
]

Außerdem müssen Sie in der Manifestdatei alle Gerätetypen deklarieren, auf die Sie zugreifen möchten, um Fingerabdruck zu verhindern. Jeder USB-Gerätetyp entspricht einem Paar aus Anbieter-ID und Produkt-ID (VID/PID). Sie können usb.getDevices verwenden, um Geräte nach ihrem VID/PID-Paar aufzuzählen.

Du musst die VID/PID-Paare für jeden Gerätetyp, den du verwenden möchtest, mit der Berechtigung usbDevices in der Manifestdatei deiner App deklarieren, wie im folgenden Beispiel gezeigt:

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

Seit Chrome 57 wird die Anforderung, alle Gerätetypen im App-Manifest zu deklarieren, für Apps gelockert, die als ChromeOS-Kiosk-Apps ausgeführt werden. Für Kiosk-Apps können Sie mit dem Berechtigungsattribut interfaceClass die Berechtigung für den Zugriff auf USB-Geräte anfordern, die:

  • Implementieren einer USB-Schnittstelle einer bestimmten Schnittstellenklasse
  • eine bestimmte USB-Geräteklasse haben,

Die folgende usbDevices-Berechtigung würde beispielsweise einer App Zugriff auf alle USB-Geräte gewähren, die eine Druckerschnittstelle (Schnittstellenklassencode 7) implementieren, und auf USB-Hub-Geräte (Geräteklassencode 9):

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

Eine Liste der zulässigen interfaceClass-Werte finden Sie unter USB-Klassencodes.

Die Eigenschaft interfaceClass kann mit der Eigenschaft vendorId kombiniert werden, um nur auf USB-Geräte eines bestimmten Anbieters zuzugreifen, wie im folgenden Beispiel gezeigt:

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

Gerät finden

Verwenden Sie die Methode usb.getDevices, um festzustellen, ob ein oder mehrere Geräte mit dem System eines Nutzers verbunden sind:

chrome.usb.getDevices(enumerateDevicesOptions, callback);
Parameter (Typ)Beschreibung
EnumeratedevicesOptions (Objekt)Ein Objekt, das sowohl vendorId (long) als auch productId (long) angibt, um den richtigen Gerätetyp im Bus zu finden. In deinem Manifest muss der usbDevices-Berechtigungsbereich deklariert werden, in dem alle vendorId- und deviceId-Paare aufgelistet sind, auf die deine App zugreifen möchte.
Callback (Funktion)Wird aufgerufen, wenn die Geräteauflistung abgeschlossen ist. Der Callback wird mit einem Parameter ausgeführt, einem Array von Device-Objekten mit drei Eigenschaften: device, vendorId, productId. Die Geräteeigenschaft ist eine gleichbleibende Kennung für ein verbundenes Gerät. Er ändert sich erst, wenn das Gerät vom Stromnetz getrennt ist. Die Details der Kennung sind undurchsichtig und können sich ändern. Verlasse dich nicht auf den aktuellen Typ.
Wenn keine Geräte gefunden werden, ist das Array leer.

Beispiel:

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

Öffnen eines Geräts

Sobald die Device-Objekte zurückgegeben wurden, können Sie ein Gerät mit usb.openDevice öffnen, um einen Verbindungs-Handle zu erhalten. Die Kommunikation mit USB-Geräten ist nur über die Verbindungs-Handles möglich.

PropertyBeschreibung
GerätObjekt im usb.getDevices-Callback empfangen
Daten (Array-Zwischenspeicher)Enthält die Daten, die bei einer eingehenden Übertragung vom Gerät gesendet wurden.

Beispiel:

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

Sie können den Öffnungsvorgang mit der Methode usb.findDevices vereinfachen, die Geräte in einem Aufruf aufzählt, den Zugriff anfordert und öffnet:

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

was entspricht:

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

USB-Übertragungen und Empfang von Daten von einem Gerät

Das USB-Protokoll definiert vier Arten von Übertragungen: Steuerung, Bulk, isochron und Interrupt. Diese Übertragungen werden im Folgenden beschrieben.

Übertragungen können in beide Richtungen erfolgen: Gerät-zu-Host (eingehend) und Host-zu-Gerät (ausgehend). Aufgrund der Beschaffenheit des USB-Protokolls müssen sowohl eingehende als auch ausgehende Nachrichten vom Host initiiert werden, also vom Computer, auf dem die Chrome-App ausgeführt wird. Bei eingehenden Nachrichten (von Gerät an Host) sendet der Host (durch Ihren JavaScript-Code initiiert) eine Nachricht an das Gerät, die als „eingehend“ gekennzeichnet ist. Die Details der Nachricht hängen vom Gerät ab, enthalten jedoch in der Regel eine Identifizierung dessen, was Sie von der Nachricht anfordern. Das Gerät antwortet dann mit den angeforderten Daten. Die Antwort des Geräts wird von Chrome verarbeitet und asynchron an den Callback gesendet, den Sie in der Übertragungsmethode angeben. Eine ausgehende Nachricht (Host-to-Device) ist ähnlich, die Antwort enthält jedoch keine vom Gerät zurückgegebenen Daten.

Für jede Nachricht vom Gerät empfängt der angegebene Callback ein Ereignisobjekt mit den folgenden Eigenschaften:

PropertyBeschreibung
resultCode (Ganzzahl)0 bedeutet Erfolg; andere Werte zeigen einen Fehler an. Ein Fehlerstring kann
aus chrome.extension.lastError gelesen werden, wenn ein Fehler
angezeigt wird.
Daten (Array-Zwischenspeicher)Enthält die Daten, die bei einer eingehenden Übertragung vom Gerät gesendet wurden.

Beispiel:

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-Übertragungen

Steuerelementübertragungen werden im Allgemeinen zum Senden oder Empfangen von Konfigurations- oder Befehlsparametern an ein USB-Gerät verwendet. Die Methode „controlTransfer“ sendet bzw. liest immer den Endpunkt 0 und es ist keine claimInterface erforderlich. Die Methode ist einfach und erhält drei Parameter:

chrome.usb.controlTransfer(connectionHandle, transferInfo, transferCallback)
Parameter (Typen)Beschreibung
connectionHandleObjekt im usb.openDevice-Callback empfangen.
transferInfoParameterobjekt mit Werten aus der Tabelle unten. Weitere Informationen finden Sie in der Protokollspezifikation für USB-Geräte.
transferCallback()Wird aufgerufen, wenn die Übertragung abgeschlossen ist.

Werte für transferInfo-Objekt:

WertBeschreibung
requestType (String)„vendor“, „standard“, „class“ oder „reserviert“.
Empfänger (String)„Gerät“, „Schnittstelle“, „Endpunkt“ oder „Sonstige“.
Richtung (String)„in“ oder „out“. Die „In“-Richtung wird verwendet, um das Gerät darüber zu informieren,
dass es Informationen an den Host senden soll. Die gesamte Kommunikation auf einem USB
-Bus wird vom Host initiiert. Verwenden Sie daher eine „Eingangs“-Übertragung, damit das Gerät
Informationen zurücksenden kann.
Anfrage (Ganzzahl)Wird vom Protokoll Ihres Geräts festgelegt.
Wert (Ganzzahl)Wird vom Protokoll Ihres Geräts festgelegt.
Index (Ganzzahl)Wird vom Protokoll Ihres Geräts festgelegt.
Länge (Ganzzahl)Wird nur verwendet, wenn die Richtung „in“ ist. Informiert das Gerät darüber, dass dies die Datenmenge ist, die der Host als Antwort erwartet.
Daten (Array-Zwischenspeicher)Wird vom Protokoll deines Geräts definiert; erforderlich, wenn die Richtung „out“ lautet.

Beispiel:

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

ISOCHRONOUS-Übertragungen

Isochrone Übertragungen sind die komplexeste Art der USB-Übertragung. Sie werden häufig für Datenstreams wie Video und Ton verwendet. Um eine isochrone Übertragung (ein- oder ausgehend) zu initiieren, müssen Sie die Methode usb.isochronousTransfer verwenden:

chrome.usb.isochronousTransfer(connectionHandle, isochronousTransferInfo, transferCallback)
ParameterBeschreibung
connectionHandleObjekt im usb.openDevice-Callback empfangen.
isochronousTransferInfoParameterobjekt mit den Werten in der Tabelle unten.
transferCallback()Wird aufgerufen, wenn die Übertragung abgeschlossen ist.

Werte für isochronousTransferInfo-Objekt:

WertBeschreibung
transferInfo (Objekt)Ein Objekt mit den folgenden Attributen:
Richtung (String): „in“ oder „out“.
endpoint (Ganzzahl): wird von Ihrem Gerät definiert. In der Regel kannst du dafür ein USB-Prüftool verwenden, z. B. lsusb -v
length (Ganzzahl): wird nur verwendet, wenn die Richtung „in“ ist. Teilt dem Gerät mit, dass dies die Datenmenge ist, die der Host als Antwort erwartet.
Muss MINDESTENS packets × packetLength sein.
data (Arraybuffer): wird durch das Protokoll Ihres Geräts definiert; wird nur verwendet, wenn die Richtung „out“ ist.
Pakete (Ganzzahl)Gesamtzahl der bei dieser Übertragung erwarteten Pakete.
packageLength (Ganzzahl)Erwartete Länge jedes Pakets bei dieser Übertragung.

Beispiel:

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

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

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

BULK-Übertragungen

Bulk-Übertragungen werden in der Regel verwendet, um eine große Menge nicht zeitkritischer Daten zuverlässig zu übertragen. usb.bulkTransfer hat drei Parameter:

chrome.usb.bulkTransfer(connectionHandle, transferInfo, transferCallback);
ParameterBeschreibung
connectionHandleObjekt im usb.openDevice-Callback empfangen.
transferInfoParameterobjekt mit den Werten in der Tabelle unten.
transferCallbackWird aufgerufen, wenn die Übertragung abgeschlossen ist.

Werte für transferInfo-Objekt:

WertBeschreibung
Richtung (String)„in“ oder „out“.
Endpunkt (Ganzzahl)Wird vom Protokoll Ihres Geräts festgelegt.
Länge (Ganzzahl)Wird nur verwendet, wenn die Richtung „in“ ist. Informiert das Gerät darüber, dass dies die Datenmenge ist, die der Host als Antwort erwartet.
Daten (ArrayBuffer)Wird vom Protokoll Ihres Geräts definiert; wird nur verwendet, wenn die Richtung „out“ lautet.

Beispiel:

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

Übertragungen mit INTERRUPT

Unterbrochene Übertragungen werden für eine kleine Menge zeitkritischer Daten verwendet. Da die gesamte USB-Kommunikation vom Host initiiert wird, fragt Hostcode in der Regel regelmäßig das Gerät ab und sendet Unterbrechungs-IN-Übertragungen, wodurch das Gerät Daten zurücksendet, wenn sich etwas in der vom Gerät gepflegten Unterbrechungswarteschlange befindet. usb.interruptTransfer hat drei Parameter:

chrome.usb.interruptTransfer(connectionHandle, transferInfo, transferCallback);
ParameterBeschreibung
connectionHandleObjekt im usb.openDevice-Callback empfangen.
transferInfoParameterobjekt mit den Werten in der Tabelle unten.
transferCallbackWird aufgerufen, wenn die Übertragung abgeschlossen ist. Beachten Sie, dass dieser Callback nicht die Antwort des Geräts enthält. Der Zweck des Callbacks besteht darin, Ihrem Code mitzuteilen, dass die asynchronen Übertragungsanfragen verarbeitet wurden.

Werte für transferInfo-Objekt:

WertBeschreibung
Richtung (String)„in“ oder „out“.
Endpunkt (Ganzzahl)Wird vom Protokoll Ihres Geräts festgelegt.
Länge (Ganzzahl)Wird nur verwendet, wenn die Richtung „in“ ist. Informiert das Gerät darüber, dass dies die Datenmenge ist, die der Host als Antwort erwartet.
Daten (ArrayBuffer)Wird vom Protokoll Ihres Geräts definiert; wird nur verwendet, wenn die Richtung „out“ lautet.

Beispiel:

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

Wichtige Hinweise

Nicht alle Geräte können über die USB API aufgerufen werden. Im Allgemeinen ist ein Zugriff auf Geräte nicht möglich, da entweder der Kernel des Betriebssystems oder ein nativer Treiber sie vom Userspace-Code zurückhält. Einige Beispiele sind Geräte mit HID-Profilen auf OSX-Systemen sowie USB-Sticks.

Auf den meisten Linux-Systemen haben USB-Geräte standardmäßig schreibgeschützte Berechtigungen. Um ein Gerät über diese API zu öffnen, muss auch Ihr Nutzer Schreibzugriff darauf haben. Eine einfache Lösung besteht darin, eine udev-Regel festzulegen. Erstellen Sie eine Datei /etc/udev/rules.d/50-yourdevicename.rules mit folgendem Inhalt:

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

Starten Sie dann einfach den udev-Daemon neu: service udev restart. Mit den folgenden Schritten können Sie prüfen, ob die Geräteberechtigungen richtig festgelegt sind:

  • Führen Sie lsusb aus, um die Bus- und Gerätenummern zu ermitteln.
  • Führen Sie ls -al /dev/bus/usb/[bus]/[device] aus. Diese Datei sollte der Gruppe „plugdev“ gehören und Schreibberechtigungen für die Gruppe haben.

Ihre App kann dies nicht automatisch tun, da hierfür Root-Zugriff erforderlich ist. Wir empfehlen, Endnutzern Anleitungen zur Verfügung zu stellen und einen Link zum Abschnitt Einschränkungen auf dieser Seite bereitzustellen, wo eine Erläuterung verfügbar ist.

Rufen Sie unter ChromeOS einfach usb.requestAccess auf. Der Berechtigungsbroker übernimmt dies für Sie.