Perangkat USB

Dokumen ini menjelaskan cara menggunakan USB API untuk berkomunikasi dengan perangkat USB. Beberapa perangkat tidak dapat diakses melalui USB API (lihat bagian Peringatan di bawah untuk detailnya). Aplikasi Chrome juga dapat terhubung ke perangkat serial dan Bluetooth.

Untuk mengetahui informasi latar belakang tentang USB, lihat spesifikasi USB resmi. USB di NutShell adalah kursus kilat yang wajar yang mungkin bermanfaat bagi Anda.

Persyaratan manifes

USB API memerlukan izin "usb" di file manifes:

"permissions": [
  "usb"
]

Selain itu, untuk mencegah pelacakan sidik jari, Anda harus mendeklarasikan semua jenis perangkat yang ingin diakses dalam file manifes. Setiap jenis perangkat USB sesuai dengan pasangan ID vendor/ID produk (VID/PID). Anda dapat menggunakan usb.getDevices untuk menghitung perangkat berdasarkan pasangan VID/PID-nya.

Anda harus mendeklarasikan pasangan VID/PID untuk setiap jenis perangkat yang ingin digunakan dengan izin usbDevices di file manifes aplikasi Anda, seperti ditunjukkan dalam contoh di bawah:

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

Mulai versi Chrome 57, persyaratan untuk mendeklarasikan semua jenis perangkat dalam manifes aplikasi dilonggarkan untuk aplikasi yang berjalan sebagai aplikasi kios ChromeOS. Untuk aplikasi kios, Anda dapat menggunakan properti izin interfaceClass untuk meminta izin guna mengakses perangkat USB yang:

  • mengimplementasikan antarmuka USB dari kelas antarmuka tertentu
  • memiliki kelas perangkat USB tertentu

Misalnya, izin usbDevices berikut akan memberikan akses aplikasi ke semua perangkat USB yang menerapkan antarmuka printer (kode class antarmuka 7), dan ke perangkat hub USB (kode class perangkat 9):

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

Untuk daftar nilai interfaceClass yang dapat diterima, lihat Kode Kelas USB.

Properti interfaceClass dapat digabungkan dengan properti vendorId untuk mendapatkan akses hanya ke perangkat USB dari vendor tertentu, seperti yang ditunjukkan oleh contoh berikut:

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

Mencari perangkat

Untuk menentukan apakah satu atau beberapa perangkat tertentu terhubung ke sistem pengguna, gunakan metode usb.getDevices:

chrome.usb.getDevices(enumerateDevicesOptions, callback);
Parameter (jenis)Deskripsi
EnumerateDevicesOptions (objek)Objek yang menentukan vendorId (panjang) dan productId (panjang) digunakan untuk menemukan jenis perangkat yang tepat di bus. Manifes Anda harus mendeklarasikan bagian izin usbDevices yang mencantumkan semua pasangan vendorId dan deviceId yang ingin diakses oleh aplikasi Anda.
callback (fungsi)Dipanggil saat enumerasi perangkat selesai. Callback akan dieksekusi dengan satu parameter, array objek Device dengan tiga properti: device, vendorId, productId. Properti perangkat adalah ID yang stabil untuk perangkat yang terhubung. Setelan ini tidak akan berubah hingga perangkat dicabut dari pengisi daya. Detail ID buram dan dapat berubah. Jangan mengandalkan jenisnya saat ini.
Jika tidak ada perangkat yang ditemukan, array akan kosong.

Contoh:

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

Membuka perangkat

Setelah objek Device ditampilkan, Anda dapat membuka perangkat menggunakan usb.openDevice untuk mendapatkan handle koneksi. Anda hanya dapat berkomunikasi dengan perangkat USB menggunakan tuas koneksi.

PropertiDeskripsi
perangkatObjek diterima di callback usb.getDevices.
data (arraybuffer)Berisi data yang dikirim oleh perangkat jika transfer masuk.

Contoh:

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

Untuk menyederhanakan proses pembukaan, Anda dapat menggunakan metode usb.findDevices, yang menghitung, meminta akses, dan membuka perangkat dalam satu panggilan:

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

yang setara dengan:

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

Mentransfer USB dan menerima data dari perangkat

Protokol USB menentukan empat jenis transfer: control, bulk, isokronus, dan interrupt. Transfer ini dijelaskan di bawah.

Transfer dapat terjadi di kedua arah: perangkat-ke-host (masuk), dan host-ke-perangkat (keluar). Karena sifat protokol USB, pesan masuk dan keluar harus dimulai oleh host (komputer yang menjalankan aplikasi Chrome). Untuk pesan masuk (perangkat ke host), host (yang dimulai oleh kode JavaScript) mengirimkan pesan yang ditandai sebagai "masuk" ke perangkat. Detail pesan bergantung pada perangkat, tetapi biasanya akan memiliki beberapa identifikasi tentang apa yang Anda minta darinya. Perangkat kemudian merespons dengan data yang diminta. Respons perangkat ditangani oleh Chrome dan dikirim secara asinkron ke callback yang Anda tentukan dalam metode transfer. Pesan keluar (host-ke-perangkat) serupa, tetapi responsnya tidak berisi data yang ditampilkan dari perangkat.

Untuk setiap pesan dari perangkat, callback yang ditentukan akan menerima objek peristiwa dengan properti berikut:

PropertiDeskripsi
resultCode (bilangan bulat)0 adalah berhasil; nilai lain menunjukkan kegagalan. String error dapat
dibaca dari chrome.extension.lastError jika kegagalan
diindikasikan.
data (arraybuffer)Berisi data yang dikirim oleh perangkat jika transfer masuk.

Contoh:

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 transfer

Transfer kontrol umumnya digunakan untuk mengirim atau menerima parameter konfigurasi atau perintah ke perangkat USB. Metode controlTransfer selalu mengirim ke/membaca dari endpoint 0, dan tidak memerlukanclaimInterface. Metode ini sederhana dan menerima tiga parameter:

chrome.usb.controlTransfer(connectionHandle, transferInfo, transferCallback)
Parameter (jenis)Deskripsi
connectionHandleObjek diterima di callback usb.openDevice.
transferInfoObjek parameter dengan nilai dari tabel di bawah. Periksa spesifikasi protokol perangkat USB untuk mengetahui detailnya.
transferCallback()Dipanggil saat transfer selesai.

Nilai untuk objek transferInfo:

NilaiDeskripsi
requestType (string)"vendor", "standard", "class", atau "reserve".
penerima (string)"device", "interface", "endpoint", atau "other".
arah ({i>string<i})"in" atau "out". Arah "masuk" digunakan untuk memberi tahu perangkat bahwa
harus mengirimkan informasi ke host. Semua komunikasi pada bus USB
diawali oleh host, jadi gunakan transfer "dalam" agar perangkat dapat
mengirim kembali informasi.
permintaan (bilangan bulat)Ditentukan oleh protokol perangkat Anda.
nilai (bilangan bulat)Ditentukan oleh protokol perangkat Anda.
indeks (bilangan bulat)Ditentukan oleh protokol perangkat Anda.
panjang (bilangan bulat)Hanya digunakan saat arahnya "masuk". Memberi tahu perangkat bahwa ini adalah jumlah data yang diharapkan host sebagai respons.
data (arraybuffer)Ditentukan oleh protokol perangkat Anda, diperlukan saat arahnya "keluar".

Contoh:

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

Transfer ISOCHRONOUS

Transfer isokronus adalah jenis transfer USB yang paling kompleks. Mereka biasanya digunakan untuk aliran data, seperti video dan suara. Untuk memulai transfer isokronous (baik masuk atau keluar), Anda harus menggunakan metode usb.isochronousTransfer:

chrome.usb.isochronousTransfer(connectionHandle, isochronousTransferInfo, transferCallback)
ParameterDeskripsi
connectionHandleObjek diterima di callback usb.openDevice.
isochronousTransferInfoObjek parameter dengan nilai dalam tabel di bawah.
transferCallback()Dipanggil saat transfer selesai.

Nilai untuk objek isochronousTransferInfo:

NilaiDeskripsi
transferInfo (objek)Objek dengan atribut berikut:
direction (string): "in" atau "out".
endpoint (integer): ditentukan oleh perangkat Anda. Biasanya dapat ditemukan dengan melihat alat instrospeksi USB, seperti lsusb -v
panjang (bilangan bulat): hanya digunakan saat arahnya "masuk". Memberi tahu perangkat bahwa ini adalah jumlah data yang diharapkan host dalam respons.
Minimal harus packets × packetLength.
data (array-buffer): ditentukan oleh protokol perangkat; hanya digunakan saat arah "keluar".
paket (bilangan bulat)Jumlah total paket yang diharapkan dalam transfer ini.
paketLength (bilangan bulat)Perkiraan panjang setiap paket dalam transfer ini.

Contoh:

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

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

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

Transfer BULK

Transfer massal biasanya digunakan untuk mentransfer sejumlah besar data yang tidak sensitif waktu dengan cara yang dapat diandalkan. usb.bulkTransfer memiliki tiga parameter:

chrome.usb.bulkTransfer(connectionHandle, transferInfo, transferCallback);
ParameterDeskripsi
connectionHandleObjek diterima di callback usb.openDevice.
transferInfoObjek parameter dengan nilai dalam tabel di bawah.
transferCallbackDipanggil saat transfer selesai.

Nilai untuk objek transferInfo:

NilaiDeskripsi
arah ({i>string<i})"in" atau "out".
endpoint (bilangan bulat)Ditentukan oleh protokol perangkat Anda.
panjang (bilangan bulat)Hanya digunakan saat arahnya "masuk". Memberi tahu perangkat bahwa ini adalah jumlah data yang diharapkan host sebagai respons.
data (ArrayBuffer)Ditentukan oleh protokol perangkat Anda; hanya digunakan saat arahnya "keluar".

Contoh:

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

Transfer INTERRUPT

Transfer interupsi digunakan untuk data sensitif waktu dalam jumlah kecil. Karena semua komunikasi USB dimulai oleh host, kode host biasanya melakukan polling perangkat secara berkala, mengirimkan transfer interupsi IN yang akan membuat perangkat mengirim data kembali jika ada sesuatu dalam antrean interupsi (dikelola oleh perangkat). usb.interruptTransfer memiliki tiga parameter:

chrome.usb.interruptTransfer(connectionHandle, transferInfo, transferCallback);
ParameterDeskripsi
connectionHandleObjek diterima di callback usb.openDevice.
transferInfoObjek parameter dengan nilai dalam tabel di bawah.
transferCallbackDipanggil saat transfer selesai. Perhatikan bahwa callback ini tidak berisi respons perangkat. Tujuan callback hanya untuk memberi tahu kode Anda bahwa permintaan transfer asinkron telah diproses.

Nilai untuk objek transferInfo:

NilaiDeskripsi
arah ({i>string<i})"in" atau "out".
endpoint (bilangan bulat)Ditentukan oleh protokol perangkat Anda.
panjang (bilangan bulat)Hanya digunakan saat arahnya "masuk". Memberi tahu perangkat bahwa ini adalah jumlah data yang diharapkan host sebagai respons.
data (ArrayBuffer)Ditentukan oleh protokol perangkat Anda; hanya digunakan saat arahnya "keluar".

Contoh:

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

Peringatan

Tidak semua perangkat dapat diakses melalui USB API. Secara umum, perangkat tidak dapat diakses karena kernel Sistem Operasi atau driver native menahannya dari kode ruang pengguna. Beberapa contohnya adalah perangkat dengan profil HID di sistem OSX, dan drive pena USB.

Pada sebagian besar sistem Linux, perangkat USB dipetakan dengan izin hanya-baca secara default. Untuk membuka perangkat melalui API ini, pengguna juga harus memiliki akses tulis ke perangkat tersebut. Solusi sederhananya adalah dengan menetapkan aturan udev. Buat file /etc/udev/rules.d/50-yourdevicename.rules dengan konten berikut:

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

Kemudian, cukup mulai ulang daemon udev: service udev restart. Anda dapat memeriksa apakah izin perangkat telah ditetapkan dengan benar dengan mengikuti langkah-langkah berikut:

  • Jalankan lsusb untuk menemukan nomor bus dan perangkat.
  • Jalankan ls -al /dev/bus/usb/[bus]/[device]. File ini harus dimiliki oleh grup "plugdev" dan memiliki izin tulis grup.

Aplikasi Anda tidak dapat melakukannya secara otomatis karena prosedur ini memerlukan akses root. Sebaiknya Anda memberikan petunjuk kepada pengguna akhir dan menyediakan link ke bagian Peringatan di halaman ini untuk mendapatkan penjelasan.

Di ChromeOS, cukup panggil usb.requestAccess. Pialang izin melakukannya untuk Anda.