Membuat perangkat untuk WebUSB

Bangun perangkat untuk memanfaatkan sepenuhnya WebUSB API.

Artikel ini menjelaskan cara membuat perangkat untuk memanfaatkan sepenuhnya WebUSB API. Untuk pengantar singkat tentang API itu sendiri, lihat Mengakses Perangkat USB di Web.

Latar belakang

Universal Serial Bus (USB) telah menjadi antarmuka fisik yang paling umum untuk menghubungkan periferal ke perangkat komputasi desktop dan seluler. Selain menentukan karakteristik listrik bus dan model umum untuk berkomunikasi dengan perangkat, spesifikasi USB menyertakan serangkaian spesifikasi class perangkat. Ini adalah model umum untuk kelas perangkat tertentu seperti penyimpanan, audio, video, jaringan, dll. yang dapat diterapkan oleh produsen perangkat. Keuntungan dari spesifikasi class perangkat ini adalah vendor sistem operasi dapat menerapkan satu driver berdasarkan spesifikasi class ("driver class") dan perangkat apa pun yang menerapkan class tersebut akan didukung. Ini adalah peningkatan yang sangat besar dibandingkan dengan setiap produsen yang perlu menulis driver perangkat mereka sendiri.

Namun, beberapa perangkat tidak sesuai dengan salah satu class perangkat standar ini. Produsen dapat memilih untuk memberi label pada perangkat mereka sebagai menerapkan class khusus vendor. Dalam hal ini, sistem operasi memilih driver perangkat yang akan dimuat berdasarkan informasi yang diberikan dalam paket driver vendor, biasanya sekumpulan ID vendor dan produk yang diketahui menerapkan protokol khusus vendor tertentu.

Fitur lain dari USB adalah perangkat dapat menyediakan beberapa antarmuka ke host yang terhubung. Setiap antarmuka dapat mengimplementasikan class standar atau khusus vendor. Saat sistem operasi memilih driver yang tepat untuk menangani perangkat, setiap antarmuka dapat diklaim oleh driver yang berbeda. Misalnya, webcam USB biasanya menyediakan dua antarmuka, satu mengimplementasikan class video USB (untuk kamera) dan satu lagi menerapkan class audio USB (untuk mikrofon). Sistem operasi tidak memuat satu "driver webcam", tetapi memuat driver class video dan audio independen yang bertanggung jawab atas fungsi terpisah perangkat. Komposisi class antarmuka ini memberikan fleksibilitas yang lebih besar.

Dasar-dasar API

Banyak class USB standar memiliki API web yang sesuai. Misalnya, halaman dapat merekam video dari perangkat class video menggunakan getUserMedia() atau menerima peristiwa input dari perangkat class antarmuka manusia (HID) dengan memproses KeyboardEvents atau PointerEvents, atau dengan menggunakan Gamepad atau WebHID API. Sama seperti tidak semua perangkat menerapkan definisi class standar, tidak semua perangkat mengimplementasikan fitur yang sesuai dengan API platform web yang ada. Jika hal ini terjadi, WebUSB API dapat mengisi kesenjangan tersebut dengan menyediakan cara bagi situs untuk mengklaim antarmuka khusus vendor dan menerapkan dukungan untuknya langsung dari dalam halaman mereka.

Persyaratan spesifik agar perangkat dapat diakses melalui WebUSB sedikit bervariasi dari satu platform ke platform lainnya karena perbedaan cara sistem operasi mengelola perangkat USB, tetapi persyaratan dasarnya adalah perangkat tidak boleh sudah memiliki driver yang mengklaim antarmuka yang ingin dikontrol halaman. Ini dapat berupa driver class generik yang disediakan oleh vendor OS atau driver perangkat yang disediakan oleh vendor. Karena perangkat USB dapat menyediakan beberapa antarmuka, yang masing-masing memiliki driver sendiri, Anda dapat membuat perangkat yang beberapa antarmukanya diklaim oleh driver dan sebagian lainnya dibiarkan dapat diakses oleh browser.

Misalnya, keyboard USB kelas atas dapat menyediakan antarmuka class HID yang akan diklaim oleh subsistem input sistem operasi dan antarmuka khusus vendor yang tetap tersedia untuk WebUSB agar dapat digunakan oleh alat konfigurasi. Alat ini dapat ditayangkan di situs produsen yang memungkinkan pengguna mengubah aspek perilaku perangkat seperti tombol makro dan efek pencahayaan tanpa menginstal software khusus platform apa pun. Deskriptor konfigurasi perangkat tersebut akan terlihat seperti ini:

Nilai Kolom Deskripsi
Deskripsi konfigurasi
0x09 bLength Ukuran deskripsi ini
0x02 bDescriptorType Deskripsi konfigurasi
0x0039 wTotalLength Total panjang rangkaian deskriptor ini
0x02 bNumInterfaces Jumlah antarmuka
0x01 bConfigurationValue Konfigurasi 1
0x00 iConfiguration Nama konfigurasi (tidak ada)
0b1010000 bmAttributes Perangkat yang dapat diaktifkan sendiri dengan pengaktifan jarak jauh
0x32 bMaxPower Daya Maksimal dinyatakan dalam kelipatan 2 mA
Deskripsi antarmuka
0x09 bLength Ukuran deskripsi ini
0x04 bDescriptorType Deskripsi antarmuka
0x00 bInterfaceNumber Antarmuka 0
0x00 bAlternateSetting Setelan alternatif 0 (default)
0x01 bNumEndpoints 1 endpoint
0x03 bInterfaceClass Class antarmuka HID
0x01 bInterfaceSubClass Subclass antarmuka booting
0x01 bInterfaceProtocol Keyboard
0x00 iInterface Nama antarmuka (tidak ada)
Deskripsi HID
0x09 bLength Ukuran deskripsi ini
0x21 bDescriptorType Deskripsi HID
0x0101 bcdHID HID versi 1.1
0x00 bCountryCode Negara target hardware
0x01 bNumDescriptors Jumlah deskriptor class HID yang harus diikuti
0x22 bDescriptorType Jenis deskripsi laporan
0x003F wDescriptorLength Panjang total deskripsi Laporan
Deskripsi endpoint
0x07 bLength Ukuran deskripsi ini
0x05 bDescriptorType Deskripsi endpoint
0b10000001 bEndpointAddress Endpoint 1 (IN)
0b00000011 bmAttributes Interupsi
0x0008 wMaxPacketSize Paket 8 byte
0x0A bInterval Interval 10 md
Deskripsi antarmuka
0x09 bLength Ukuran deskripsi ini
0x04 bDescriptorType Deskripsi antarmuka
0x01 bInterfaceNumber Antarmuka 1
0x00 bAlternateSetting Setelan alternatif 0 (default)
0x02 bNumEndpoints 2 endpoint
0xFF bInterfaceClass Class antarmuka khusus vendor
0x00 bInterfaceSubClass
0x00 bInterfaceProtocol
0x00 iInterface Nama antarmuka (tidak ada)
Deskripsi endpoint
0x07 bLength Ukuran deskripsi ini
0x05 bDescriptorType Deskripsi endpoint
0b10000010 bEndpointAddress Endpoint 1 (IN)
0b00000010 bmAttributes Massal
0x0040 wMaxPacketSize Paket 64 byte
0x00 bInterval T/A untuk endpoint massal
Deskripsi endpoint
0x07 bLength Ukuran deskripsi ini
0x05 bDescriptorType Deskripsi endpoint
0b00000011 bEndpointAddress Endpoint 3 (KELUAR)
0b00000010 bmAttributes Massal
0x0040 wMaxPacketSize Paket 64 byte
0x00 bInterval T/A untuk endpoint massal

Deskripsi konfigurasi terdiri dari beberapa deskripsi yang digabungkan bersama. Masing-masing dimulai dengan kolom bLength dan bDescriptorType sehingga dapat diidentifikasi. Antarmuka pertama adalah antarmuka HID dengan deskriptor HID terkait dan satu endpoint yang digunakan untuk mengirim peristiwa input ke sistem operasi. Antarmuka kedua adalah antarmuka khusus vendor dengan dua endpoint yang dapat digunakan untuk mengirim perintah ke perangkat dan menerima respons sebagai gantinya.

Deskripsi WebUSB

Meskipun WebUSB dapat berfungsi dengan banyak perangkat tanpa modifikasi firmware, fungsi tambahan diaktifkan dengan menandai perangkat dengan deskriptor tertentu yang menunjukkan dukungan untuk WebUSB. Misalnya, Anda dapat menentukan URL halaman landing tempat browser dapat mengarahkan pengguna saat perangkat Anda dicolokkan.

Screenshot notifikasi WebUSB di Chrome
Notifikasi WebUSB.

Object Store Perangkat Biner (BOS) adalah konsep yang diperkenalkan di USB 3.0, tetapi juga telah di-backport ke perangkat USB 2.0 sebagai bagian dari versi 2.1. Mendeklarasikan dukungan untuk WebUSB dimulai dengan menyertakan Deskripsi Kemampuan Platform berikut dalam deskripsi BOS:

Nilai Kolom Deskripsi
Deskripsi Object Store perangkat biner
0x05 bLength Ukuran deskripsi ini
0x0F bDescriptorType Deskripsi Object Store perangkat biner
0x001D wTotalLength Total panjang rangkaian deskriptor ini
0x01 bNumDeviceCaps Jumlah deskriptor kemampuan perangkat dalam BOS
Deskripsi kemampuan platform WebUSB
0x18 bLength Ukuran deskripsi ini
0x10 bDescriptorType Deskripsi kemampuan perangkat
0x05 bDevCapabilityType Deskripsi kemampuan platform
0x00 bReserved
{0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65} PlatformCapablityUUID GUID deskripsi kemampuan platform WebUSB dalam format little-endian
0x0100 bcdVersion Deskriptor WebUSB versi 1.0
0x01 bVendorCode Nilai bRequest untuk WebUSB
0x01 iLandingPage URL untuk halaman landing

UUID kemampuan platform mengidentifikasinya sebagai deskripsi Kemampuan Platform WebUSB, yang memberikan informasi dasar tentang perangkat. Agar browser dapat mengambil informasi selengkapnya tentang perangkat, browser menggunakan nilai bVendorCode untuk mengeluarkan permintaan tambahan ke perangkat. Satu-satunya permintaan yang saat ini ditentukan adalah GET_URL yang menampilkan deskripsi URL. Deskriptor ini mirip dengan deskriptor string, tetapi dirancang untuk mengenkode URL dalam byte paling kecil. Deskriptor URL untuk "https://google.com" akan terlihat seperti ini:

Nilai Kolom Deskripsi
Deskripsi URL
0x0D bLength Ukuran deskripsi ini
0x03 bDescriptorType Deskripsi URL
0x01 bScheme https://
"google.com" URL Konten URL yang dienkode UTF-8

Saat perangkat Anda pertama kali dicolokkan, browser akan membaca deskripsi BOS dengan mengeluarkan transfer kontrol GET_DESCRIPTOR standar ini:

bmRequestType bRequest wValue wIndex wLength Data (respons)
0b10000000 0x06 0x0F00 0x0000 * Deskripsi BOS

Permintaan ini biasanya dilakukan dua kali, pertama kali dengan wLength yang cukup besar sehingga host mengetahui nilai kolom wTotalLength tanpa melakukan transfer besar, lalu lagi saat panjang deskripsi penuh diketahui.

Jika deskriptor WebUSB Platform Capability memiliki kolom iLandingPage yang ditetapkan ke nilai bukan nol, browser kemudian melakukan permintaan GET_URL khusus WebUSB dengan mengeluarkan transfer kontrol dengan bRequest yang ditetapkan ke nilai bVendorCode dari deskriptor kemampuan platform dan wValue ditetapkan ke nilai iLandingPage. Kode permintaan untuk GET_URL (0x02) dimasukkan ke wIndex:

bmRequestType bRequest wValue wIndex wLength Data (respons)
0b11000000 0x01 0x0001 0x0002 * Deskripsi URL

Sekali lagi, permintaan ini dapat dikeluarkan dua kali untuk terlebih dahulu memeriksa durasi deskripsi yang dibaca.

Pertimbangan khusus platform

Meskipun WebUSB API berupaya menyediakan antarmuka yang konsisten untuk mengakses perangkat USB, developer tetap harus mengetahui persyaratan yang diberlakukan pada aplikasi seperti persyaratan browser web untuk mengakses perangkat.

macOS

Tidak ada yang khusus diperlukan untuk macOS. Situs yang menggunakan WebUSB dapat terhubung ke perangkat dan mengklaim antarmuka apa pun yang tidak diklaim oleh driver kernel atau aplikasi lain.

Linux

Linux mirip dengan macOS, tetapi secara default sebagian besar distribusi tidak menyiapkan akun pengguna dengan izin untuk membuka perangkat USB. Daemon sistem yang disebut udev bertanggung jawab untuk menetapkan pengguna dan grup yang diizinkan untuk mengakses perangkat. Aturan seperti ini akan menetapkan kepemilikan perangkat yang cocok dengan ID vendor dan ID produk tertentu ke grup plugdev yang merupakan grup umum bagi pengguna yang memiliki akses ke periferal:

SUBSYSTEM=="usb", ATTR{idVendor}=="XXXX", ATTR{idProduct}=="XXXX", GROUP="plugdev"

Ganti XXXX dengan ID produk dan vendor heksadesimal untuk perangkat Anda, misalnya ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e11" akan cocok dengan ponsel Nexus One. Ini harus ditulis tanpa awalan "0x" biasa dan semua huruf kecil agar dapat dikenali dengan benar. Untuk menemukan ID perangkat Anda, jalankan alat command line lsusb.

Aturan ini harus ditempatkan dalam file di direktori /etc/udev/rules.d dan diterapkan segera setelah perangkat dicolokkan. Anda tidak perlu memulai ulang udev.

Android

Platform Android didasarkan pada Linux, tetapi tidak memerlukan modifikasi apa pun pada konfigurasi sistem. Secara default, setiap perangkat yang tidak memiliki driver yang di-build ke dalam sistem operasi tersedia untuk browser. Namun, developer harus mengetahui bahwa pengguna akan mengalami langkah tambahan saat terhubung ke perangkat. Setelah pengguna memilih perangkat sebagai respons terhadap panggilan ke requestDevice(), Android akan menampilkan perintah yang menanyakan apakah akan mengizinkan Chrome mengaksesnya. Permintaan ini juga akan muncul kembali jika pengguna kembali ke situs yang sudah memiliki izin untuk terhubung ke perangkat dan situs memanggil open().

Selain itu, lebih banyak perangkat yang akan dapat diakses di Android daripada di Linux desktop karena lebih sedikit driver yang disertakan secara default. Penghapusan yang signifikan, misalnya, adalah class USB CDC-ACM yang biasanya diterapkan oleh adaptor USB-ke-serial karena tidak ada API di Android SDK untuk berkomunikasi dengan perangkat serial.

ChromeOS

ChromeOS juga berbasis Linux dan juga tidak memerlukan modifikasi apa pun pada konfigurasi sistem. Layanan permissions_broker mengontrol akses ke perangkat USB dan akan mengizinkan browser mengaksesnya selama ada setidaknya satu antarmuka yang belum diklaim.

Windows

Model driver Windows memperkenalkan persyaratan tambahan. Tidak seperti platform di atas, kemampuan untuk membuka perangkat USB dari aplikasi pengguna bukan default, meskipun tidak ada driver yang dimuat. Sebagai gantinya, ada driver khusus, WinUSB, yang perlu dimuat untuk menyediakan antarmuka yang digunakan aplikasi untuk mengakses perangkat. Hal ini dapat dilakukan dengan file informasi driver (INF) kustom yang diinstal di sistem atau dengan mengubah firmware perangkat untuk memberikan Deskripsi Kompatibilitas OS Microsoft selama enumerasi.

File Informasi Driver (INF)

File informasi driver memberi tahu Windows apa yang harus dilakukan saat menemukan perangkat untuk pertama kalinya. Karena sistem pengguna sudah menyertakan driver WinUSB, semuanya diperlukan agar file INF mengaitkan vendor dan ID produk Anda dengan aturan penginstalan baru ini. File di bawah ini adalah contoh dasar. Simpan ke file dengan ekstensi .inf, ubah bagian yang ditandai dengan "X", lalu klik kanan dan pilih "Instal" dari menu konteks.

[Version]
Signature   = "$Windows NT$"
Class       = USBDevice
ClassGUID   = {88BAE032-5A81-49f0-BC3D-A4FF138216D6}
Provider    = %ManufacturerName%
CatalogFile = WinUSBInstallation.cat
DriverVer   = 09/04/2012,13.54.20.543

; ========== Manufacturer/Models sections ===========

[Manufacturer]
%ManufacturerName% = Standard,NTx86,NTia64,NTamd64

[Standard.NTx86]
%USB\MyCustomDevice.DeviceDesc% = USB_Install,USB\VID_XXXX&PID_XXXX

[Standard.NTia64]
%USB\MyCustomDevice.DeviceDesc% = USB_Install,USB\VID_XXXX&PID_XXXX

[Standard.NTamd64]
%USB\MyCustomDevice.DeviceDesc% = USB_Install,USB\VID_XXXX&PID_XXXX

; ========== Class definition ===========

[ClassInstall32]
AddReg = ClassInstall_AddReg

[ClassInstall_AddReg]
HKR,,,,%ClassName%
HKR,,NoInstallClass,,1
HKR,,IconPath,%REG_MULTI_SZ%,"%systemroot%\system32\setupapi.dll,-20"
HKR,,LowerLogoVersion,,5.2

; =================== Installation ===================

[USB_Install]
Include = winusb.inf
Needs   = WINUSB.NT

[USB_Install.Services]
Include = winusb.inf
Needs   = WINUSB.NT.Services

[USB_Install.HW]
AddReg = Dev_AddReg

[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"

; =================== Strings ===================

[Strings]
ManufacturerName              = "Your Company Name Here"
ClassName                     = "Your Company Devices"
USB\MyCustomDevice.DeviceDesc = "Your Device Name Here"

Bagian [Dev_AddReg] mengonfigurasi kumpulan DeviceInterfaceGUID untuk perangkat. Setiap antarmuka perangkat harus memiliki GUID agar aplikasi dapat menemukan dan menghubungkannya melalui Windows API. Gunakan cmdlet PowerShell New-Guid atau alat online untuk membuat GUID acak.

Untuk tujuan pengembangan, alat Zadig menyediakan antarmuka yang mudah untuk mengganti driver yang dimuat untuk antarmuka USB dengan driver WinUSB.

Deskripsi kompatibilitas OS Microsoft

Pendekatan file INF di atas rumit karena mengharuskan konfigurasi setiap mesin pengguna terlebih dahulu. Windows 8.1 dan yang lebih tinggi menawarkan alternatif melalui penggunaan deskriptor USB khusus. Deskripsi ini memberikan informasi ke sistem operasi Windows saat perangkat pertama kali dicolokkan yang biasanya disertakan dalam file INF.

Setelah menyiapkan deskripsi WebUSB, Anda juga dapat dengan mudah menambahkan deskripsi kompatibilitas OS Microsoft. Pertama, perluas deskriptor BOS dengan deskriptor kemampuan platform tambahan ini. Pastikan untuk memperbarui wTotalLength dan bNumDeviceCaps untuk memperhitungkannya.

Nilai Kolom Deskripsi
Deskripsi kemampuan platform Microsoft OS 2.0
0x1C bLength Ukuran deskripsi ini
0x10 bDescriptorType Deskripsi kemampuan perangkat
0x05 bDevCapabilityType Deskripsi kemampuan platform
0x00 bReserved
{0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F} PlatformCapablityUUID GUID deskripsi kompatibilitas platform Microsoft OS 2.0 dalam format little-endian
0x06030000 dwWindowsVersion Versi Windows minimum yang kompatibel (Windows 8.1)
0x00B2 wMSOSDescriptorSetTotalLength Total panjang kumpulan deskripsi
0x02 bMS_VendorCode Nilai bRequest untuk mengambil deskripsi Microsoft lebih lanjut
0x00 bAltEnumCode Perangkat tidak mendukung enumerasi alternatif

Seperti halnya deskripsi WebUSB, Anda harus memilih nilai bRequest untuk digunakan oleh transfer kontrol yang terkait dengan deskripsi ini. Dalam contoh ini, saya telah memilih 0x02. 0x07, yang ditempatkan di wIndex, adalah perintah untuk mengambil Set Deskripsi Microsoft OS 2.0 dari perangkat.

bmRequestType bRequest wValue wIndex wLength Data (respons)
0b11000000 0x02 0x0000 0x0007 * Kumpulan Deskripsi MS OS 2.0

Perangkat USB dapat memiliki beberapa fungsi sehingga bagian pertama dari kumpulan deskripsi menjelaskan fungsi yang terkait dengan properti yang mengikutinya. Contoh di bawah mengonfigurasi antarmuka 1 perangkat komposit. Deskriptor memberi OS dua informasi penting tentang antarmuka ini. Deskripsi ID yang kompatibel memberi tahu Windows bahwa perangkat ini kompatibel dengan driver WinUSB. Deskripsi properti registry berfungsi mirip dengan bagian [Dev_AddReg] dari contoh INF di atas, yang menetapkan properti registry untuk menetapkan GUID antarmuka perangkat ke fungsi ini.

Nilai Kolom Deskripsi
Header kumpulan deskripsi Microsoft OS 2.0
0x000A wLength Ukuran deskripsi ini
0x0000 wDescriptorType Deskripsi header kumpulan deskripsi
0x06030000 dwWindowsVersion Versi Windows minimum yang kompatibel (Windows 8.1)
0x00B2 wTotalLength Total panjang kumpulan deskripsi
Header subset konfigurasi Microsoft OS 2.0
0x0008 wLength Ukuran deskripsi ini
0x0001 wDescriptorType Deskripsi header subset konfigurasi.
0x00 bConfigurationValue Berlaku untuk konfigurasi 1 (diindeks dari 0 meskipun konfigurasi biasanya diindeks dari 1)
0x00 bReserved Harus ditetapkan ke 0
0x00A8 wTotalLength Total panjang subset termasuk header ini
Header subset fungsi Microsoft OS 2.0
0x0008 wLength Ukuran deskripsi ini
0x0002 wDescriptorType Deskripsi header subset fungsi
0x01 bFirstInterface Antarmuka pertama fungsi
0x00 bReserved Harus ditetapkan ke 0
0x00A0 wSubsetLength Total panjang subset termasuk header ini
Deskriptor ID yang kompatibel dengan Microsoft OS 2.0
0x0014 wLength Ukuran deskripsi ini
0x0003 wDescriptorType Deskripsi ID yang kompatibel
"WINUSB\0\0" CompatibileID String ASCII yang ditambahkan padding hingga 8 byte
"\0\0\0\0\0\0\0\0" SubCompatibleID String ASCII yang ditambahkan padding hingga 8 byte
Deskriptor properti registry Microsoft OS 2.0
0x0084 wLength Ukuran deskripsi ini
0x0004 wDescriptorType Deskripsi properti registry
0x0007 wPropertyDataType REG_MULTI_SZ
0x002A wPropertyNameLength Panjang nama properti
"DeviceInterfaceGUIDs\0" PropertyName Nama properti dengan terminator null yang dienkode dalam UTF-16LE
0x0050 wPropertyDataLength Panjang nilai properti
"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}\0\0" PropertyData GUID plus dua terminator null yang dienkode dalam UTF-16LE

Windows hanya akan mengkueri perangkat untuk informasi ini satu kali. Jika perangkat tidak merespons dengan deskripsi yang valid, perangkat tidak akan bertanya lagi saat perangkat terhubung lagi. Microsoft telah menyediakan daftar Entri Registry Perangkat USB yang menjelaskan entri registry yang dibuat saat menghitung perangkat. Saat menguji, hapus entri yang dibuat untuk perangkat agar Windows mencoba membaca deskriptor lagi.

Untuk informasi selengkapnya, lihat postingan blog Microsoft tentang cara menggunakan deskripsi ini.

Contoh

Contoh kode yang menerapkan perangkat yang mendukung WebUSB yang menyertakan deskripsi WebUSB dan deskripsi Microsoft OS dapat ditemukan di project ini: