4 This document describes how to use the
<a href=
"usb">USB API
</a> to communicate
5 with USB devices. Some devices are not accessible through the USB API
6 (see the
<a href=
"#caveats">Caveats
</a> section below for details).
7 Chrome Apps can also connect to
<a href=
"serial">serial
</a> and
8 <a href=
"bluetooth">Bluetooth
</a> devices.
12 <b>Samples:
</b> For examples that illustrate how Chrome Apps can connect to hardware devices, see the
13 <a href=
"https://github.com/GoogleChrome/chrome-app-samples/tree/master/samples/serial">serial
</a>,
14 <a href=
"https://github.com/GoogleChrome/chrome-app-samples/tree/master/samples/servo">servo
</a>, and
15 <a href=
"https://github.com/GoogleChrome/chrome-app-samples/tree/master/samples/usb">usb
</a> samples.
19 For background information about USB, see the official
20 <a href=
"http://www.usb.org/home">USB specifications
</a>.
<br/>
21 <a href=
"http://www.beyondlogic.org/usbnutshell/usb1.shtml">
22 <i>USB in a NutShell
</i></a>
23 is a reasonable crash course that you may find helpful.
26 <h2 id=
"manifest">Manifest requirement
</h2>
28 <p>The USB API requires the
"usb" permission in the manifest file:
</p>
30 <pre data-filename=
"manifest.json">
36 <p>In addition, in order to prevent
37 <a href=
"http://en.wikipedia.org/wiki/Device_fingerprint">finger-printing
</a>,
38 you must declare all the device types you want to access in the manifest file.
39 Each type of USB device corresponds to a vendor id/product id (VID/PID) pair.
40 You can use $(ref:usb.getDevices) to enumerate devices by their VID/PID
44 You must declare the VID/PID pairs for each type of device you want to use
45 under the
"usbDevices" permission in your app's manifest file, as shown in the
48 <pre data-filename=
"manifest.json">
61 <p class=
"note">Note that only decimal numbers are allowed in JSON format.
62 You cannot use hexadecimal numbers in these fields.
</p>
64 <h2 id=
"finding_device">Finding a device
</h2>
67 To determine whether one or more specific devices are connected to a user's
68 system, use the $(ref:usb.getDevices) method:
72 chrome.usb.getDevices(enumerateDevicesOptions, callback);
77 <table class=
"simple">
79 <th scope=
"col">Parameter (type)
</th>
80 <th scope=
"col">Description
</th>
83 <td>EnumerateDevicesOptions (object)
</td>
84 <td>An object specifying both a
<code>vendorId
</code> (long) and
85 <code>productId
</code> (long) used to find the correct type of device on
86 the bus. Your manifest must declare the
<code>usbDevices
</code> permission
87 section listing all the
<code>vendorId
</code> and
<code>deviceId
</code>
88 pairs your app wants to access.
92 <td>callback (function)
</td>
93 <td>Called when the device enumeration is finished. The callback will be
94 executed with one parameter, an array of
<code>Device
</code> objects with
95 three properties:
<code>device
</code>,
<code>vendorId
</code>,
96 <code>productId
</code>. The device property is a stable identifier for a
97 connected device. It will not change until the device is unplugged. The
98 detail of the identifier is opaque and subject to change. Do not rely on
99 its current type.
<br/>
100 If no devices are found, the array will be empty.
108 function onDeviceFound(devices) {
109 this.devices=devices;
111 if (devices.length
> 0) {
112 console.log(
"Device(s) found: "+devices.length);
114 console.log(
"Device could not be found");
117 console.log(
"Permission denied.");
121 chrome.usb.getDevices({
"vendorId": vendorId,
"productId": productId}, onDeviceFound);
124 <h2 id=
"usb_open">Opening a device
</h2>
126 Once the
<code>Device
</code> objects are returned, you can open a device using
127 usb.openDevice to obtain a connection handle. You can only
128 communicate with USB devices using connection handles.
131 <table class=
"simple">
133 <th scope=
"col">Property
</th>
134 <th scope=
"col">Description
</th>
138 <td>Object received in $(ref:usb.getDevices) callback.
</td>
141 <td>data (arraybuffer)
</td>
142 <td>Contains the data sent by the device if the transfer was inbound.
</td>
149 var usbConnection = null;
150 var onOpenCallback = function(connection) {
152 usbConnection = connection;
153 console.log(
"Device opened.");
155 console.log(
"Device failed to open.");
159 chrome.usb.openDevice(device, onOpenCallback);
163 Not every device can be opened successfully. In general, operating systems
164 lock down many types of USB interfaces (e.g. keyboards and mice, mass storage
165 devices, webcams, etc.) and they cannot be claimed by user applications.
166 On Linux (other than Chrome OS), once an interface of a device is locked down by
167 the OS, the whole device is locked down (because all the interfaces shares the
168 same device file), even if the other interfaces of the device can be used in
169 theory. On Chrome OS, you can request access to unlocked interfaces using the
170 $(ref:usb.requestAccess) method. If permitted, the permission broker will
171 unlock the device file for you.
175 To simplify the opening process, you can use the $(ref:usb.findDevices)
176 method, which enumerates, requests access, and opens devices in one call:
180 chrome.usb.findDevices({
"vendorId": vendorId,
"productId": productId,
"interfaceId": interfaceId}, callback);
182 <p>which is equivalent to:
</p>
184 chrome.usb.getDevices({
"vendorId": vendorId,
"productId": productId}, function (devices) {
186 console.log(
"Error enumerating devices.");
190 var connections = [], pendingAccessRequests = devices.length;
191 devices.forEach(function (device) {
192 chrome.usb.requestAccess(interfaceId, function () {
193 // No need to check for errors at this point.
194 // Nothing can be done if an error occurs anyway. You should always try
195 // to open the device.
196 chrome.usb.openDevices(device, function (connection) {
197 if (connection) connections.push(connection);
198 pendingAccessRequests--;
199 if (pendingAccessRequests ==
0) {
200 callback(connections);
208 <h2 id=
"usb_transfers">USB transfers and receiving data from a device
</h2>
211 The USB protocol defines four types of transfers:
212 <a href=
"#control_transfers">control
</a>,
213 <a href=
"#bulk_transfers">bulk
</a>,
214 <a href=
"#isochronous_transfers">isochronous
</a>
215 and
<a href=
"#interrupt_transfers">interrupt
</a>.
216 These transfers are described below.
220 Transfers can occur in both directions: device-to-host (inbound), and
221 host-to-device (outbound). Due to the nature of the USB protocol,
222 both inbound and outbound messages must be initiated by the host (the
223 computer that runs the Chrome app).
224 For inbound (device-to-host) messages, the host (initiated by your JavaScript
225 code) sends a message flagged as
"inbound" to the device.
226 The details of the message depend on the device, but usually will have
227 some identification of what you are requesting from it.
228 The device then responds with the requested data.
229 The device's response is handled by Chrome and delivered asynchronously to the
230 callback you specify in the transfer method.
231 An outbound (host-to-device) message is similar, but the response doesn't
232 contain data returned from the device.
236 For each message from the device, the specified callback will receive an event
237 object with the following properties:
242 <table class=
"simple">
244 <th scope=
"col">Property
</th>
245 <th scope=
"col">Description
</th>
248 <td>resultCode (integer)
</td>
249 <td>0 is success; other values indicate failure. An error string can be
<br/>
250 read from
<code>chrome.extension.lastError
</code> when a failure is
<br/>
255 <td>data (arraybuffer)
</td>
256 <td>Contains the data sent by the device if the transfer was inbound.
</td>
263 var onTransferCallback = function(event) {
264 if (event && event.resultCode ===
0 && event.data) {
265 console.log(
"got " + event.data.byteLength +
" bytes");
269 chrome.usb.bulkTransfer(connectionHandle, transferInfo, onTransferCallback);
272 <h2 id=
"control_transfers">CONTROL transfers
</h2>
274 <p>Control transfers are generally used to send or receive configuration or
275 command parameters to a USB device. The controlTransfer method always sends
276 to/reads from endpoint
0, and no claimInterface is required.
277 The method is simple and receives three parameters:
</p>
280 chrome.usb.controlTransfer(connectionHandle, transferInfo, transferCallback)
285 <table class=
"simple">
287 <th scope=
"col">Parameter (types)
</th>
288 <th scope=
"col">Description
</th>
291 <td>connectionHandle
</td>
292 <td>Object received in $(ref:usb.openDevice) callback.
296 <td>transferInfo
</td>
297 <td>Parameter object with values from the table below. Check your USB
298 device protocol specification for details.
302 <td>transferCallback()
</td>
303 <td>Invoked when the transfer has completed.
</td>
309 <code>transferInfo
</code>
313 <table class=
"simple">
315 <th scope=
"col">Value
</th>
316 <th scope=
"col">Description
</th>
319 <td>requestType (string)
</td>
320 <td>"vendor",
"standard",
"class" or
"reserved".
</td>
323 <td>recipient (string)
</td>
324 <td>"device",
"interface",
"endpoint" or
"other".
</td>
327 <td>direction (string)
</td>
328 <td>"in" or
"out". The
"in" direction is used to notify the device that
<br/>
329 it should send information to the host. All communication on a USB
<br/>
330 bus is host-initiated, so use an
"in" transfer to allow a device to
<br/>
331 send information back.
335 <td>request (integer)
</td>
336 <td>Defined by your device's protocol.
</td>
339 <td>value (integer)
</td>
340 <td>Defined by your device's protocol.
</td>
343 <td>index (integer)
</td>
344 <td>Defined by your device's protocol.
</td>
347 <td>length (integer)
</td>
348 <td>Only used when direction is
"in". Notifies the device that this is
349 the amount of data the host is expecting in response.
353 <td>data (arraybuffer)
</td>
354 <td>Defined by your device's protocol, required when direction is
364 "requestType":
"vendor",
365 "recipient":
"device",
370 // Note that the ArrayBuffer, not the TypedArray itself is used.
371 "data": new Uint8Array([
4,
8,
15,
16,
23,
42]).buffer
373 chrome.usb.controlTransfer(connectionHandle, transferInfo, optionalCallback);
376 <h2 id=
"isochronous_transfers">ISOCHRONOUS transfers
</h2>
378 <p>Isochronous transfers are the most complex type of USB transfer. They are
379 commonly used for streams of data, like video and sound. To initiate an
380 isochronous transfer (either inbound or outbound), you must use
381 the $(ref:usb.isochronousTransfer) method:
</p>
384 chrome.usb.isochronousTransfer(connectionHandle, isochronousTransferInfo, transferCallback)
389 <table class=
"simple">
391 <th scope=
"col">Parameter
</th>
392 <th scope=
"col">Description
</th>
395 <td>connectionHandle
</td>
396 <td>Object received in $(ref:usb.openDevice) callback.
400 <td>isochronousTransferInfo
</td>
401 <td>Parameter object with the values in the table below.
</td>
404 <td>transferCallback()
</td>
405 <td>Invoked when the transfer has completed.
</td>
411 <code>isochronousTransferInfo
</code>
415 <table class=
"simple">
417 <th scope=
"col">Value
</th>
418 <th scope=
"col">Description
</th>
421 <td>transferInfo (object)
</td>
422 <td>An object with the following attributes:
<br/>
423 <b>direction (string):
</b>"in" or
"out".
<br/>
424 <b>endpoint (integer):
</b>defined by your device. Usually can be found by
425 looking at an USB instrospection tool, like
<code>lsusb -v
</code><br/>
426 <b>length (integer):
</b>only
427 used when direction is
"in". Notifies the device that this is the amount
428 of data the host is expecting in response.
<br/>
430 Should be AT LEAST
<code>packets
</code> × <code>packetLength
</code>.
432 <b>data (arraybuffer):
</b>defined by your device's protocol;
433 only used when direction is
"out".
437 <td>packets (integer)
</td>
438 <td>Total number of packets expected in this transfer.
</td>
441 <td>packetLength (integer)
</td>
442 <td>Expected length of each packet in this transfer.
</td>
455 var isoTransferInfo = {
456 "transferInfo": transferInfo,
461 chrome.usb.isochronousTransfer(connectionHandle, isoTransferInfo, optionalCallback);
465 <b>Notes:
</b> One isochronous transfer will contain
466 <code>isoTransferInfo.packets
</code> packets of
467 <code>isoTransferInfo.packetLength
</code> bytes.
468 If it is an inbound transfer (your code requested data from the device), the
469 <code>data
</code> field in the onUsbEvent will be an ArrayBuffer of size
470 <code>transferInfo.length
</code>. It is your duty to walk through this
471 ArrayBuffer and extract the different packets, each starting at a multiple of
472 <code>isoTransferInfo.packetLength
</code> bytes.
<br/>
474 If you are expecting a stream of data from the device, remember that
475 you will have to send one
"inbound" transfer for each transfer you expect
476 back. USB devices don't send transfers to the USB bus unless the host
477 explicitly requests them through
"inbound" transfers.
480 <h2 id=
"bulk_transfers">BULK transfers
</h2>
482 <p>Bulk transfers are commonly used to transfer a large amount of
483 non-time-sensitive data in a reliable way.
484 $(ref:usb.bulkTransfer) has three parameters:
</p>
487 chrome.usb.bulkTransfer(connectionHandle, transferInfo, transferCallback);
492 <table class=
"simple">
494 <th scope=
"col">Parameter
</th>
495 <th scope=
"col">Description
</th>
498 <td>connectionHandle
</td>
499 <td>Object received in $(ref:usb.openDevice) callback.
503 <td>transferInfo
</td>
504 <td>Parameter object with the values in the table below.
</td>
507 <td>transferCallback
</td>
508 <td>Invoked when the transfer has completed.
</td>
514 <code>transferInfo
</code>
518 <table class=
"simple">
520 <th scope=
"col">Value
</th>
521 <th scope=
"col">Description
</th>
524 <td>direction (string)
</td>
525 <td>"in" or
"out".
</td>
528 <td>endpoint (integer)
</td>
529 <td>Defined by your device's protocol.
</td>
532 <td>length (integer)
</td>
533 <td>Only used when direction is
"in". Notifies the device that this is
534 the amount of data the host is expecting in response.
538 <td>data (ArrayBuffer)
</td>
539 <td>Defined by your device's protocol; only used when direction is
551 "data": new Uint8Array([
4,
8,
15,
16,
23,
42]).buffer
555 <h2 id=
"interrupt_transfers">INTERRUPT transfers
</h2>
557 <p>Interrupt transfers are used to small amount of time sensitive data.
558 Since all USB communication is initiated by the host, host code usually polls
559 the device periodically, sending interrupt IN transfers that will make the
560 device send data back if there is anything in the interrupt queue (maintained
562 $(ref:usb.interruptTransfer) has three parameters:
</p>
565 chrome.usb.interruptTransfer(connectionHandle, transferInfo, transferCallback);
570 <table class=
"simple">
572 <th scope=
"col">Parameter
</th>
573 <th scope=
"col">Description
</th>
576 <td>connectionHandle
</td>
577 <td>Object received in $(ref:usb.openDevice) callback.
581 <td>transferInfo
</td>
582 <td>Parameter object with the values in the table below.
</td>
585 <td>transferCallback
</td>
586 <td>Invoked when the transfer has completed. Notice that this callback
587 doesn't contain the device's response. The purpose of the callback is
588 simply to notify your code that the asynchronous transfer requests has
595 Values for
<code>transferInfo
</code> object:
598 <table class=
"simple">
600 <th scope=
"col">Value
</th>
601 <th scope=
"col">Description
</th>
604 <td>direction (string)
</td>
605 <td>"in" or
"out".
</td>
608 <td>endpoint (integer)
</td>
609 <td>Defined by your device's protocol.
</td>
612 <td>length (integer)
</td>
613 <td>Only used when direction is
"in". Notifies the device that this is
614 the amount of data the host is expecting in response.
618 <td>data (ArrayBuffer)
</td>
619 <td>Defined by your device's protocol; only used when direction is
633 chrome.usb.interruptTransfer(connectionHandle, transferInfo, optionalCallback);
636 <h2 id=
"caveats">Caveats
</h2>
638 <p>Not all devices can be accessed through the USB API. In general, devices
639 are not accessible because either the Operating System's kernel or a native
640 driver holds them off from user space code. Some examples are devices with
641 HID profiles on OSX systems, and USB pen drives.
</p>
644 On most Linux systems, USB devices are mapped with read-only permissions by
645 default. To open a device through this API, your user will need to have
646 write access to it too.
647 A simple solution is to set a udev rule. Create a file
648 <code>/etc/udev/rules.d/
50-yourdevicename.rules
</code>
649 with the following content:
653 SUBSYSTEM==
"usb", ATTR{idVendor}==
"[yourdevicevendor]",
MODE=
"0664",
GROUP=
"plugdev"
657 Then, just restart the udev daemon:
<code>service udev restart
</code>.
658 You can check if device permissions are set correctly by following these
663 <li>Run
<code>lsusb
</code> to find the bus and device numbers.
</li>
664 <li>Run
<code>ls -al /dev/bus/usb/[bus]/[device]
</code>. This file should be
665 owned by group
"plugdev" and have group write permissions.
669 <p>Your app cannot do this automatically since this this procedure requires root
670 access. We recommend that you provide instructions to end-users and link to the
671 <a href=
"#caveats">Caveats
</a> section on this page for an explanation.
</p>
673 <p>On Chrome OS, simply call $(ref:usb.requestAccess). The permission
674 broker does this for you.
</p>