Interfejs WebUSB API zwiększa bezpieczeństwo i łatwość korzystania z USB dzięki umieszczeniu go w internecie.
Jeśli powiedziałem przejrzyście i po prostu „USB”, jest duża szansa, że pomyśl o klawiaturach, myszach, urządzeniach audio, wideo i urządzeniach pamięci masowej. To już Do wyboru są jednak inne rodzaje urządzeń tam.
Te niestandaryzowane urządzenia USB wymagają dostawców sprzętu do zapisu danych związanych z określoną platformą sterowniki i pakiety SDK, aby umożliwić korzystanie z nich (deweloperowi). Ten kod związany z konkretną platformą uniemożliwiał dotychczas używanie tych urządzeń przez internet. A to jeden z powodów, dla których stworzyliśmy interfejs WebUSB API: pozwalają na udostępnianie w internecie usług urządzeń USB. Dzięki temu interfejsowi API sprzęt producenci będą mogli tworzyć pakiety SDK JavaScript działające na różnych platformach, urządzenia.
Jednak przede wszystkim zwiększy to bezpieczeństwo i wygodę korzystania z USB dzięki w internecie.
Zobaczmy, jak działa interfejs WebUSB API:
- Kup urządzenie USB.
- Podłącz go do komputera. Powiadomienie pojawi się od razu, po prawej stronie strona, która się wyświetla na tym urządzeniu.
- Kliknij powiadomienie. Strona internetowa istnieje i jest gotowa do użycia.
- Kliknij, aby połączyć, a w Chrome pojawi się moduł wyboru urządzeń USB, wybierz swoje urządzenie.
Tadam!
Jak wygląda ta procedura bez interfejsu WebUSB API?
- zainstalować aplikację dla konkretnej platformy,
- Jeśli mój system operacyjny obsługuje tę funkcję, sprawdź, czy została pobrana jest właściwa.
- Zainstaluj to. Przy odrobinie szczęścia nie będziesz otrzymywać żadnych przerażających promptów i wyskakujących okienek w systemie operacyjnym ostrzeżenie dotyczące instalowania sterowników/aplikacji z internetu. Jeśli jeśli masz pecha, zainstalowane sterowniki lub aplikacje działają nieprawidłowo, Twój komputer. (Pamiętaj, że internet został zbudowany tak, aby zawierać błędy stronach internetowych).
- Jeśli użyjesz funkcji tylko raz, kod pozostanie na komputerze do momentu o jego usunięciu. (W internecie miejsce na nieużywane reclaimed.)
Zanim zacznę
W tym artykule zakładamy, że masz już podstawową wiedzę o działaniu USB. Jeśli nie, zalecamy przeczytanie artykułu USB in a NutShell. Podstawowe informacje na temat USB: znajdziesz w oficjalnej specyfikacji urządzenia USB.
Interfejs WebUSB API jest dostępny w Chrome 61.
Dostępne w przypadku testowania origin
Aby uzyskać jak najwięcej opinii od programistów korzystających z WebUSB API, ale tę funkcję dodaliśmy wcześniej w Chrome 54 i Chrome. 57 jako pierwotną wersję próbną.
Ostatni okres próbny zakończył się we wrześniu 2017 r.
Prywatność i bezpieczeństwo
Tylko HTTPS
Ze względu na zaawansowane możliwości działa ona tylko w przypadku bezpiecznych kontekstów. Oznacza to, że pamiętaj o TLS.
Wymagany gest użytkownika
Ze względów bezpieczeństwa navigator.usb.requestDevice()
może
może być wywoływana gestem użytkownika, na przykład dotknięciem lub kliknięciem.
Zasady dotyczące uprawnień
Zasady dotyczące uprawnień to mechanizm, który umożliwia programistom selektywne włączanie oraz wyłączyć różne funkcje i interfejsy API przeglądarki. Można ją zdefiniować za pomocą protokołu HTTP nagłówek i/lub element iframe „allow” .
Możesz zdefiniować zasadę uprawnień, która określa, czy atrybut usb
ma być
widoczne na obiekcie Navigator, lub innymi słowy po zezwoleniu na WebUSB.
Poniżej znajduje się przykład zasady nagłówka, w której niedozwolony jest protokół WebUSB:
Feature-Policy: fullscreen "*"; usb "none"; payment "self" https://payment.example.com
Poniżej znajdziesz inny przykład zasad dotyczących kontenerów, w których dozwolone jest użycie USB:
<iframe allowpaymentrequest allow="usb; fullscreen"></iframe>
Zacznij kodować
Interfejs WebUSB API w dużym stopniu opiera się na obietnicach JavaScriptu. Jeśli nie znasz usługi,
zapoznaj się z tym świetnym samouczkiem. Jeszcze jedno, () => {}
to po prostu funkcje strzałek ECMAScript 2015.
Uzyskaj dostęp do urządzeń USB
Możesz poprosić użytkownika o wybranie jednego podłączonego urządzenia USB za pomocą
navigator.usb.requestDevice()
lub zadzwoń pod numer navigator.usb.getDevices()
, aby otrzymać
Lista wszystkich podłączonych urządzeń USB, do których strona ma dostęp.
Funkcja navigator.usb.requestDevice()
przyjmuje wymagany obiekt JavaScript
która definiuje filters
. Te filtry pozwalają dopasować dowolne urządzenie USB do
danego dostawcy (vendorId
) i opcjonalnie (productId
) produktu.
Klucze classCode
, protocolCode
, serialNumber
i subclassCode
mogą
która również powinna być tu zdefiniowana.
Oto jak uzyskać dostęp do połączonego urządzenia Arduino skonfigurowanego aby zezwolić na źródło.
navigator.usb.requestDevice({ filters: [{ vendorId: 0x2341 }] })
.then(device => {
console.log(device.productName); // "Arduino Micro"
console.log(device.manufacturerName); // "Arduino LLC"
})
.catch(error => { console.error(error); });
Zanim spytasz, nie wymyśliłem magicznej liczby szesnastkowej 0x2341
numer. Po prostu wyszukiwałem słowo „Arduino” na tej liście identyfikatorów USB.
USB device
zwróconego w ramach powyższej obietnicy ma pewne podstawowe, ale
ważne informacje o urządzeniu, takie jak obsługiwana wersja USB,
maksymalnego rozmiaru pakietu, dostawcy i identyfikatora produktu, liczby możliwych
konfiguracji urządzeń. Zasadniczo zawiera on wszystkie pola
deskryptor USB urządzenia.
// Get all connected USB devices the website has been granted access to.
navigator.usb.getDevices().then(devices => {
devices.forEach(device => {
console.log(device.productName); // "Arduino Micro"
console.log(device.manufacturerName); // "Arduino LLC"
});
})
Przy okazji: jeśli urządzenie USB informuje o obsłudze WebUSB, zdefiniuje adres URL strony docelowej, a Chrome będzie wyświetlać trwałe powiadomienie, gdy Podłączono urządzenie USB. Kliknięcie go spowoduje otwarcie strony docelowej.
Porozmawiaj z płytą USB Arduino
Teraz zobaczmy, jak łatwo można się komunikować przy użyciu interfejsu zgodnego z WebUSB. Płytka Arduino przez port USB. Sprawdź instrukcje na stronie Na stronie https://github.com/webusb/arduino włącz WebUSB swoje szkice.
Bez obaw. W dalszej części artykułu omówię wszystkie metody korzystania z urządzenia WebUSB związane z urządzeniami. ten artykuł.
let device;
navigator.usb.requestDevice({ filters: [{ vendorId: 0x2341 }] })
.then(selectedDevice => {
device = selectedDevice;
return device.open(); // Begin a session.
})
.then(() => device.selectConfiguration(1)) // Select configuration #1 for the device.
.then(() => device.claimInterface(2)) // Request exclusive control over interface #2.
.then(() => device.controlTransferOut({
requestType: 'class',
recipient: 'interface',
request: 0x22,
value: 0x01,
index: 0x02})) // Ready to receive data
.then(() => device.transferIn(5, 64)) // Waiting for 64 bytes of data from endpoint #5.
.then(result => {
const decoder = new TextDecoder();
console.log('Received: ' + decoder.decode(result.data));
})
.catch(error => { console.error(error); });
Pamiętaj, że biblioteka WebUSB, której używam, to tylko implementacja przykładowego protokołu (opartego na standardowym protokole szeregowym USB) oraz producenci mogą tworzyć dowolne zestawy i typy punktów końcowych; Transfery ustawień są szczególnie przydatne w przypadku małych poleceń konfiguracyjnych, zyskują priorytet autobusowy i mają dobrze zdefiniowany strukturę.
A oto szkic, który przesłano na płytkę Arduino.
// Third-party WebUSB Arduino library
#include <WebUSB.h>
WebUSB WebUSBSerial(1 /* https:// */, "webusb.github.io/arduino/demos");
#define Serial WebUSBSerial
void setup() {
Serial.begin(9600);
while (!Serial) {
; // Wait for serial port to connect.
}
Serial.write("WebUSB FTW!");
Serial.flush();
}
void loop() {
// Nothing here for now.
}
Używana w przykładowym powyżej bibliotece WebUSB Arduino innej firmy zasadniczo 2 rzeczy:
- Urządzenie działa jak urządzenie WebUSB, umożliwiając Chrome odczytanie adresu URL strony docelowej.
- Udostępnia interfejs WebUSB Serial API, którego możesz użyć do zastąpienia domyślnego.
Spójrz jeszcze raz na kod JavaScript. Gdy już dostanę wybrany przez użytkownika element (device
),
device.open()
uruchamia wszystkie kroki potrzebne na danej platformie, aby rozpocząć sesję przy użyciu USB
urządzenia. Następnie muszę wybrać dostępną konfigurację USB –
device.selectConfiguration()
Pamiętaj, że konfiguracja określa sposób
zasilane urządzenie, maksymalne zużycie energii i liczbę interfejsów.
A jeśli już mowa o interfejsach, to muszę też poprosić o dostęp na wyłączność za pomocą
device.claimInterface()
, ponieważ dane można przenieść tylko do interfejsu lub
powiązanych punktów końcowych po zgłoszeniu własności interfejsu. Ostatnie połączenie
Aplikacja device.controlTransferOut()
jest niezbędna do skonfigurowania urządzenia Arduino z
odpowiednie polecenia do komunikowania się przez interfejs WebUSB Serial API.
Następnie device.transferIn()
wykonuje przelew zbiorczy na
który informuje, że host jest gotowy do przyjmowania danych zbiorczych. Następnie funkcja
obiekt typu result
zawiera obiekt DataView data
, który
wymaga odpowiedniej analizy.
Jeśli masz doświadczenie w korzystaniu z USB, wszystko to powinno wyglądać znajomo.
Chcę więcej
Interfejs WebUSB API umożliwia interakcję ze wszystkimi typami punktów końcowych/transferu USB:
- Transfery za pomocą funkcji CONTROL – używane do wysyłania i odbierania konfiguracji lub poleceń
do urządzenia USB są obsługiwane za pomocą
controlTransferIn(setup, length)
icontrolTransferOut(setup, data)
. - transfery INTERRUPT, używane przez krótki czas, są
obsługiwane za pomocą tych samych metod, co transfery BULK z
transferIn(endpointNumber, length)
itransferOut(endpointNumber, data)
. - Przesyłanie ISOCHRONOUS, używane w przypadku strumieni danych, takich jak wideo i dźwięk, jest
obsługiwane za pomocą
isochronousTransferIn(endpointNumber, packetLengths)
iisochronousTransferOut(endpointNumber, data, packetLengths)
- transfery BULK służące do przesyłania dużej ilości danych, które nie są wrażliwe czasowo
w niezawodny sposób i są obsługiwane za pomocą
transferIn(endpointNumber, length)
oraztransferOut(endpointNumber, data)
Możesz też obejrzeć projekt WebLight Mike'a Tsao, to wzorcowy przykład konstrukcji urządzenia LED sterowanego przez USB, które zostało zaprojektowane dla interfejsu WebUSB API (bez użycia Arduino). Znajdziesz tam informacje o sprzęcie, oprogramowaniu i oprogramowania układowego.
Unieważnianie dostępu do urządzenia USB
Strona może wyczyścić uprawnienia dostępu do urządzenia USB, którego już nie potrzebuje
wywołując funkcję forget()
w instancji USBDevice
. Na przykład w przypadku adresu
edukacyjna aplikacja internetowa używana na współdzielonym komputerze z wieloma urządzeniami, duża
zbyt duża liczba pozwoleń wywołanych przez użytkowników wpływa negatywnie na wrażenia użytkowników.
// Voluntarily revoke access to this USB device.
await device.forget();
Funkcja forget()
jest dostępna w Chrome 101 i nowszych wersjach, więc sprawdź, czy jest ona
obsługiwane przez:
if ("usb" in navigator && "forget" in USBDevice.prototype) {
// forget() is supported.
}
Ograniczenia rozmiaru transferu
Niektóre systemy operacyjne nakładają ograniczenia na ilość danych, które mogą być przesyłane oczekujące transakcje USB. Dzielenie danych na mniejsze transakcje tylko przesłanie kilku plików jednocześnie pozwala uniknąć tych ograniczeń. Zmniejsza też ilość używanej pamięci i umożliwia aplikacji zgłaszanie postępów Zakończono przenoszenie danych.
Wielokrotne transfery przesyłane do punktu końcowego są zawsze wykonywane w odpowiedniej kolejności, można zwiększyć przepustowość, przesyłając wiele fragmentów w kolejce, aby uniknąć opóźnienia między transferami USB. Po każdym pełnym przesłaniu fragmentu powiadom swój kod, że powinien dostarczać więcej danych zgodnie z opisem w pomocy pomocniczej poniżej.
const BULK_TRANSFER_SIZE = 16 * 1024; // 16KB
const MAX_NUMBER_TRANSFERS = 3;
async function sendRawPayload(device, endpointNumber, data) {
let i = 0;
let pendingTransfers = [];
let remainingBytes = data.byteLength;
while (remainingBytes > 0) {
const chunk = data.subarray(
i * BULK_TRANSFER_SIZE,
(i + 1) * BULK_TRANSFER_SIZE
);
// If we've reached max number of transfers, let's wait.
if (pendingTransfers.length == MAX_NUMBER_TRANSFERS) {
await pendingTransfers.shift();
}
// Submit transfers that will be executed in order.
pendingTransfers.push(device.transferOut(endpointNumber, chunk));
remainingBytes -= chunk.byteLength;
i++;
}
// And wait for last remaining transfers to complete.
await Promise.all(pendingTransfers);
}
Wskazówki
Debugowanie USB w Chrome jest łatwiejsze dzięki wewnętrznej stronie about://device-log
który umożliwia przeglądanie wszystkich zdarzeń związanych z urządzeniem USB w jednym miejscu.
Przydatne są również strony wewnętrzne about://usb-internals
, na których możesz:
symuluje podłączanie i odłączanie wirtualnych urządzeń WebUSB.
Przydaje się to do testowania interfejsu bez użycia fizycznego sprzętu.
W większości systemów Linux urządzenia USB są mapowane z uprawnieniami tylko do odczytu przez
wartość domyślną. Aby zezwolić Chrome na otwarcie urządzenia USB, musisz dodać nowy udev
. Utwórz plik pod adresem /etc/udev/rules.d/50-yourdevicename.rules
z
ta treść:
SUBSYSTEM=="usb", ATTR{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"
gdzie [yourdevicevendor]
to 2341
, jeśli Twoje urządzenie to na przykład Arduino.
Możesz też dodać ATTR{idProduct}
, aby zwiększyć szczegółowość reguły. Upewnij się, że atrybuty
user
jest członkiem grupy plugdev
. Następnie po prostu ponownie podłącz urządzenie.
Zasoby
- Stack Overflow: https://stackoverflow.com/questions/tagged/webusb
- Specyfikacja WebUSB API: http://wicg.github.io/webusb/
- Stan funkcji Chrome: https://www.chromestatus.com/feature/5651917954875392
- Problemy ze specyfikacją: https://github.com/WICG/webusb/issues
- Błędy implementacji: http://crbug.com?q=component:Blink>USB
- WebUSB ❤ ️Arduino: https://github.com/webusb/arduino
- IRC: #webusb na IRC W3C
- Lista adresowa WICG: https://lists.w3.org/Archives/Public/public-wicg/
- Projekt WebLight: https://github.com/sowbug/weblight
Wyślij tweeta na adres @ChromiumDev, używając hashtagu
#WebUSB
.
i daj nam znać, gdzie i jak go używasz.
Podziękowania
Dziękujemy Joe Medley za przeczytanie tego artykułu.