Urządzenia USB

Ten dokument opisuje, jak używać interfejsu USB API do komunikacji z urządzeniami USB. Niektóre urządzenia nie są dostępne przez interfejs USB API (więcej informacji znajdziesz w sekcji Zastrzeżenia poniżej). Aplikacje Chrome mogą też łączyć się z urządzeniami serialnymi i Bluetooth.

Podstawowe informacje na temat USB znajdziesz w oficjalnych specyfikacjach USB. USB w NutShell to rozsądny kurs na wypadek awarii, który może Ci się przydać.

Wymagania dotyczące pliku manifestu

Interfejs USB API wymaga „USB” uprawnienia w pliku manifestu:

"permissions": [
  "usb"
]

Aby zapobiec odciskom cyfrowym, musisz też zadeklarować wszystkie typy urządzeń, do którego chcesz uzyskać dostęp w pliku manifestu. Każdy typ urządzenia USB odpowiada identyfikatorowi dostawcy/produktu (VID/PID). Za pomocą funkcji usb.getDevices możesz wyliczać urządzenia według pary VID/PID.

W dokumencie usbDevices musisz zadeklarować pary VID/PID dla każdego typu urządzenia, którego chcesz używać. uprawnienia w pliku manifestu aplikacji, jak w przykładzie poniżej:

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

Od Chrome 57 wymóg definiowania wszystkich typów urządzeń w manifeście aplikacji jest w przypadku aplikacji działających jako aplikacje kiosku ChromeOS. W przypadku aplikacji kiosku możesz użyć parametru Właściwość interfaceClass do wysyłania próśb o dostęp do urządzeń USB, które:

  • zaimplementować interfejs USB określonej klasy interfejsu
  • mają określoną klasę urządzenia USB;

Na przykład poniższe uprawnienie usbDevices przyznałoby aplikacji dostęp do wszystkich urządzeń USB, które wdrożyć interfejs drukarki (kod klasy interfejsu 7) oraz urządzenia centrali USB (kod klasy urządzenia) 9):

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

Listę dopuszczalnych wartości interfaceClass znajdziesz w artykule Kody klas USB.

Usługę interfaceClass można połączyć z usługą vendorId, aby uzyskać dostęp tylko do pamięci USB urządzeń określonego dostawcy, co pokazuje następujący przykład:

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

Znajdowanie urządzenia

Aby sprawdzić, czy z systemem użytkownika jest połączone konkretne urządzenie, użyj Metoda usb.getDevices:

chrome.usb.getDevices(enumerateDevicesOptions, callback);
Parametr (typ)Opis
EnumerateDevicesOptions (obiekt)Obiekt określający właściwości vendorId (długi) i productId (długi) używany do znalezienia prawidłowego typu urządzenia magistrali. Plik manifestu musi zadeklarować sekcję uprawnień usbDevices z listą wszystkich par vendorId i deviceId, do których aplikacja chce mieć dostęp.
wywołanie zwrotne (funkcja)Wywoływane po zakończeniu wyliczania urządzenia. Wywołanie zwrotne zostanie wykonane z jednym parametrem – tablicą obiektów Device z 3 właściwościami: device, vendorId i productId. Właściwość urządzenia to stały identyfikator połączonego urządzenia. Nie zmieni się, dopóki urządzenie nie zostanie odłączone. Szczegół identyfikatora jest nieprzezroczysty i może ulec zmianie. Nie polegaj na jego bieżącym typie.
Jeśli nie znaleziono żadnych urządzeń, tablica będzie pusta.

Przykład:

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

Otwieranie urządzenia

Po zwróceniu obiektów Device możesz otworzyć urządzenie przy użyciu usb.openDevice, aby uzyskać uchwyt połączenia. Z urządzeniami USB możesz komunikować się tylko za pomocą uchwytów połączeń.

WłaściwośćOpis
urządzenieObiekt odebrany w wywołaniu zwrotnym usb.getDevices.
dane (bufor tablicy)Obejmuje dane wysłane przez urządzenie, jeśli przesyłanie było przychodzące.

Przykład:

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

Aby uprościć proces otwierania, możesz użyć metody usb.findDevices, która wylicza: prosi o dostęp i otwiera urządzenia w ramach jednej rozmowy:

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

który jest odpowiednikiem:

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

Przesyłanie danych z urządzenia przez USB i odbieranie ich

Protokół USB definiuje 4 typy transferów: control, zbiorcze, izochronologiczne i przerwać. Te transfery zostały opisane poniżej.

Przesyłanie danych może odbywać się w dwóch kierunkach: między urządzeniem a hostem (przychodzące) oraz między hostem a urządzeniem (wychodzące). Termin zgodnie z charakterem protokołu USB, zarówno wiadomości przychodzące, jak i wychodzące muszą być inicjowane przez hosta. (komputer, na którym działa aplikacja Chrome). W przypadku wiadomości przychodzących (przekazywanych z urządzenia do hosta) host (zainicjowany kod JavaScript) wysyła komunikat oznaczony jako „przychodzący”. do urządzenia. Szczegóły wiadomości zależą od urządzenia, ale zwykle zawierają informacje o tym, czego dotyczy Twoja prośba . Następnie urządzenie podaje w odpowiedzi żądane dane. Odpowiedź urządzenia jest obsługiwana przez Przeglądarka Chrome została asynchronicznie wykonywana zgodnie z wywołaniem zwrotnym określonym w metodzie transferu. Wychodzące wiadomość (host-to-urządzenie) jest podobna, ale odpowiedź nie zawiera danych zwróconych z urządzenia.

Dla każdej wiadomości z urządzenia określone wywołanie zwrotne otrzyma obiekt zdarzenia z tych właściwości:

WłaściwośćOpis
wynikCode (liczba całkowita)0 oznacza sukces. a inne wartości wskazują na niepowodzenie. Ciąg błędu może być
odczytany z narzędzia chrome.extension.lastError, jeśli wskazuje ono
niepowodzenie.
dane (bufor tablicy)Obejmuje dane wysłane przez urządzenie, jeśli przesyłanie było przychodzące.

Przykład:

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

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

Przesiadki: Control

Transfery sterujące są zwykle używane do wysyłania i odbierania konfiguracji lub parametrów poleceń na USB urządzenia. Metoda ControlTransfer zawsze wysyła do punktu końcowego 0/odczytuje ją z punktu końcowego 0 i żadna zasada claimInterface nie jest Metoda jest prosta i otrzymuje 3 parametry:

chrome.usb.controlTransfer(connectionHandle, transferInfo, transferCallback)
Parametr (typy)Opis
connectionHandleObiekt odebrano w wywołaniu zwrotnym usb.openDevice.
transferInfoObiekt parametru z wartościami z tabeli poniżej. Szczegółowe informacje znajdziesz w specyfikacji protokołu USB.
transferCallback()Wywoływana po zakończeniu przenoszenia.

Wartości obiektu transferInfo:

WartośćOpis
requestType (ciąg)„dostawca”, „standardowy”, „klasa” lub „zarezerwowane”.
odbiorca (ciąg znaków)"device", "interface", "endpoint" lub „inny”.
kierunek (ciąg znaków)„w” lub „poza”. Wyrażenie „w” jest używany do powiadomienia urządzenia,
że powinno wysłać informacje do hosta. Całość komunikacji przez autobus USB
jest inicjowana przez hosta, więc użyj parametru „in” przenieść dane, aby umożliwić urządzeniu
wysłanie informacji.
żądanie (całkowite)Zdefiniowana przez protokół urządzenia.
wartość (całkowita)Zdefiniowana przez protokół urządzenia.
indeks (liczba całkowita)Zdefiniowana przez protokół urządzenia.
długość (liczba całkowita)Używany tylko wtedy, gdy kierunek jest „w”. Powiadamia urządzenie, że takiej ilości danych oczekuje host w odpowiedzi.
dane (bufor tablicy)Zdefiniowane przez protokół urządzenia i wymagane, gdy kierunek jest „zewnętrzny”.

Przykład:

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

Przesiadki ISOCHRONOUS

Transfery izochronologiczne to najbardziej złożony typ przenoszenia danych przez USB. Zwykle są wykorzystywane w transmisjach. danych, takich jak wideo i dźwięk. Aby zainicjować przenoszenie izochronologiczne (przychodzące lub wychodzące), musi użyć metody usb.isochronousTransfer:

chrome.usb.isochronousTransfer(connectionHandle, isochronousTransferInfo, transferCallback)
ParametrOpis
connectionHandleObiekt odebrano w wywołaniu zwrotnym usb.openDevice.
isochronousTransferInfoObiekt parametru z wartościami podanymi w tabeli poniżej.
transferCallback()Wywoływana po zakończeniu przenoszenia.

Wartości obiektu isochronousTransferInfo:

WartośćOpis
transferInfo (obiekt)Obiekt o tych atrybutach:
direction (string): "in" lub „out”.
punkt końcowy (liczba całkowita): zdefiniowany przez urządzenie. Zwykle można je znaleźć w narzędziu do inspekcji USB, np. lsusb -v
długość (liczba całkowita): używana tylko wtedy, gdy kierunek to „in”. Powiadamia urządzenie, że jest to ilość danych spodziewana w odpowiedzi przez host.
Wartość powinna wynosić CO NAJMNIEJ packets × packetLength.
Dane (bufor tablicy): zdefiniowane przez protokół urządzenia; używana tylko wtedy, gdy kierunek jest „na zewnątrz”.
pakiety (liczba całkowita)Łączna liczba pakietów oczekiwana w ramach tego transferu.
packageLength (liczba całkowita)Oczekiwana długość każdego pakietu w ramach tego transferu.

Przykład:

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

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

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

Przesiadki BULK

Transfery zbiorcze są zwykle używane do przesyłania dużych ilości danych, które nie są pilne czasowo sposób. Pole usb.bulkTransfer ma 3 parametry:

chrome.usb.bulkTransfer(connectionHandle, transferInfo, transferCallback);
ParametrOpis
connectionHandleObiekt odebrano w wywołaniu zwrotnym usb.openDevice.
transferInfoObiekt parametru z wartościami podanymi w tabeli poniżej.
transferCallbackWywoływana po zakończeniu przenoszenia.

Wartości obiektu transferInfo:

WartośćOpis
kierunek (ciąg znaków)„w” lub „poza”.
punkt końcowy (liczba całkowita)Zdefiniowana przez protokół urządzenia.
długość (liczba całkowita)Używany tylko wtedy, gdy kierunek jest „w”. Powiadamia urządzenie, że takiej ilości danych oczekuje host w odpowiedzi.
dane (ArrayBuffer)Zdefiniowany przez protokół urządzenia; używana tylko wtedy, gdy kierunek jest „na zewnątrz”.

Przykład:

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

Transfery INTERRUPT

Transfery przerywane są stosowane w przypadku niewielkich ilości danych wrażliwych. Ponieważ cała komunikacja USB jest zainicjowane przez hosta, kod hosta zwykle okresowo odpytuje urządzenie, wysyłając prośbę o przerwę w działaniu urządzenia transfery, dzięki którym urządzenie będzie wysyłać dane z powrotem, jeśli coś znajdzie się w kolejce zakłóceń (obsługiwany przez urządzenie). Interfejs usb.interruptTransfer ma 3 parametry:

chrome.usb.interruptTransfer(connectionHandle, transferInfo, transferCallback);
ParametrOpis
connectionHandleObiekt odebrano w wywołaniu zwrotnym usb.openDevice.
transferInfoObiekt parametru z wartościami podanymi w tabeli poniżej.
transferCallbackWywoływana po zakończeniu przenoszenia. Zwróć uwagę, że to wywołanie zwrotne nie zawiera odpowiedzi urządzenia. Wywołanie zwrotne służy po prostu do powiadomienia Twojego kodu o przetworzeniu żądań transferu asynchronicznego.

Wartości obiektu transferInfo:

WartośćOpis
kierunek (ciąg znaków)„w” lub „poza”.
punkt końcowy (liczba całkowita)Zdefiniowana przez protokół urządzenia.
długość (liczba całkowita)Używany tylko wtedy, gdy kierunek jest „w”. Powiadamia urządzenie, że takiej ilości danych oczekuje host w odpowiedzi.
dane (ArrayBuffer)Zdefiniowany przez protokół urządzenia; używana tylko wtedy, gdy kierunek jest „na zewnątrz”.

Przykład:

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

Zastrzeżenia

Nie wszystkie urządzenia można uzyskać przez interfejs USB API. Ogólnie urządzenia są niedostępne, ponieważ Jądro systemu operacyjnego lub natywny sterownik odciąga je od kodu przestrzeni użytkownika. Niektóre np. urządzenia z profilami HID w systemach OSX oraz pamięci USB.

W większości systemów z systemem Linux urządzenia USB są domyślnie mapowane z uprawnieniami tylko do odczytu. Aby otworzyć urządzenia za pomocą tego interfejsu API, użytkownik musi mieć również uprawnienia do zapisu w nim. Prostym rozwiązaniem jest ustawić regułę udev. Utwórz plik /etc/udev/rules.d/50-yourdevicename.rules z tymi elementami treść:

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

Następnie uruchom ponownie demona udev: service udev restart. Możesz sprawdzić, czy uprawnienia urządzenia ustaw je prawidłowo, wykonując te czynności:

  • Uruchom lsusb, aby znaleźć numery autobusów i urządzeń.
  • Uruchom ls -al /dev/bus/usb/[bus]/[device]. Ten plik powinien należeć do grupy „plugdev” i mają uprawnienia do zapisu grupowego.

Twoja aplikacja nie może tego zrobić automatycznie, ponieważ ta procedura wymaga dostępu na poziomie roota. Zalecamy podaj instrukcje użytkownikom oraz link do sekcji Zastrzeżenia na tej stronie, .

W ChromeOS wystarczy wywołać usb.requestAccess. Broker uprawnień robi to za Ciebie.