Index: chrome/common/extensions/docs/server2/templates/articles/app_hardware.html |
diff --git a/chrome/common/extensions/docs/server2/templates/articles/app_hardware.html b/chrome/common/extensions/docs/server2/templates/articles/app_hardware.html |
new file mode 100644 |
index 0000000000000000000000000000000000000000..499a3ed088cecd2db836607d6f867a6ce7572b90 |
--- /dev/null |
+++ b/chrome/common/extensions/docs/server2/templates/articles/app_hardware.html |
@@ -0,0 +1,605 @@ |
+<h1 class="page_title">Accessing Hardware Devices</h1> |
+<p> |
+This doc shows you how packaged apps can connect to USB devices |
+and read from and write to a user's serial ports. |
+See also the reference docs for the |
+<a href="experimental.usb.html">USB API</a> |
+and the |
+<a href="experimental.serial.html">Serial API</a>. |
+The <a href="experimental.bluetooth.html">Bluetooth API</a> has just landed and |
+we'll write more on this soon. |
+We've included a link to an early sample below. |
+</p> |
+<p class="note"> |
+<b>API Samples: </b> |
+Want to play with the code? |
+Check out the |
+<a href="https://github.com/GoogleChrome/chrome-app-samples/tree/master/serial">serial</a>, |
+<a href="https://github.com/GoogleChrome/chrome-app-samples/tree/master/servo">servo</a>, |
+<a href="https://github.com/GoogleChrome/chrome-app-samples/tree/master/usb">usb</a>, |
+and <a href="https://github.com/GoogleChrome/chrome-app-samples/tree/master/bluetooth-demo">bluetooth-demo</a> samples. |
+</p> |
+<h2 id="usb">Accessing USB devices</h2> |
+<p> |
+You can use the USB API to send messages to any connected device. |
+</p> |
+<h3>Manifest requirement</h3> |
+<p> |
+You must add the "usb" permission |
+to the manifest file: |
+</p> |
+<pre> |
+"permissions": [ |
+ "app.window", |
+ "experimental", |
+ "usb" |
+] |
+</pre> |
+<h3>Finding a device</h3> |
+<p> |
+Every device in a USB bus is identified |
+by its vendor and product IDs. |
+To find a device, |
+use the <code>findDevice()</code> method |
+which has four parameters: |
+</p> |
+<pre> |
+chrome.experimental.usb.findDevice(vendorId, productId, eventCallbacks, onDeviceFoundCallback) |
+</pre> |
+<br> |
+<table border="0"> |
+ <tr> |
+ <th scope="col"> Parameter (type) </th> |
+ <th scope="col"> Description </th> |
+ </tr> |
+ <tr> |
+ <td>vendorId (long)</td> |
+ <td>The vendor ID for your USB device (in Linux, use lsusb to find it).</td> |
+ </tr> |
+ <tr> |
+ <td>productId (long)</td> |
+ <td>The product ID for your USB device (in Linux, use lsusb to find it).</td> |
+ </tr> |
+ <tr> |
+ <td>eventCallbacks(object)</td> |
+ <td>An object with a single key, "onEvent", |
+ to be called whenever an event occurs on the corresponding device. |
+ This will be the primary method of receiving information from the device. |
+ As the host-initiated USB protocol is complex, read on to learn more. |
+ </td> |
+ </tr> |
+ <tr> |
+ <td>onDevideFoundCallback()</td> |
+ <td>Called when the device is found. |
+ The callback's parameter is an object |
+ with three properties: <code>handle</code>, |
+ <code>vendorId</code>, |
+ <code>productId</code>; |
+ or <code>NULL</code>, |
+ if no device is found. |
+ Save this object |
+ as it's required to send messages to the device.</td> |
+ </tr> |
+</table> |
+<p> |
+Example: |
+</p> |
+<pre> |
+var onDeviceFound = function(device) { |
+ deviceObj=device; |
+ if (device) { |
+ console.log(“Device found: ”+device.handle); |
+ } else { |
+ console.log(“Device could not be found”); |
+ } |
+}; |
+var onUsbEvent = function(event) { |
+ console.log(“USB event!”); |
+}; |
+chrome.experimental.usb.findDevice(vendorId, productId, {"onEvent": onUsbEvent}, onDeviceFound); |
+</pre> |
+<h3>USB transfers and receiving data from a device</h3> |
+<p> |
+USB protocol defines four types of transfers: |
+control, bulk, isochronous and interrupt. |
+Theoretically they can all occur in both directions:<br> |
+device-to-host and host-to-device. |
+Host-to-device is initiated by your code and is described in the next sections. |
+</p> |
+<p> |
+Device-to-host messages are handled by Chrome and delivered |
+to the <code>onEvent()</code> callback |
+defined in the <code>findDevice()</code> method. |
+For each message from the device, |
+the <code>onEvent</code> callback will receive |
+an event object with the following properties: |
+</p> |
+<br> |
+<table border="0"> |
+ <tr> |
+ <th scope="col"> Property </th> |
+ <th scope="col"> Description </th> |
+ </tr> |
+ <tr> |
+ <td>type (string)</td> |
+ <td>Currently always contains the string "transferResult".</td> |
+ </tr> |
+ <tr> |
+ <td>resultCode (integer)</td> |
+ <td>0 is success; other values indicate failure.</td> |
+ </tr> |
+ <tr> |
+ <td>data (integer array)</td> |
+ <td>Contains the data sent by the device. |
+ </td> |
+ </tr> |
+</table> |
+<p> |
+Example: |
+</p> |
+<pre> |
+var onUsbEvent = function(event) { |
+ if (event && event.resultCode===0 && event.data) { |
+ console.log(“got ”+event.data.length+" bytes"); |
+ } |
+}; |
+chrome.experimental.usb.findDevice( vendorId, productId, {"onEvent": onUsbEvent}, onDeviceFound); |
+</pre> |
+<h3>Sending data - control transfers</h3> |
+<p> |
+Control transfers are generally used to send configuration |
+or command parameters to a USB device. |
+The method is simple and receives three parameters: |
+</p> |
+<pre> |
+chrome.experimental.usb.controlTransfer(deviceObj, transferInfo, transferCallback) |
+</pre> |
+<br> |
+<table border="0"> |
+ <tr> |
+ <th scope="col"> Parameter (types)</th> |
+ <th scope="col"> Description </th> |
+ </tr> |
+ <tr> |
+ <td>deviceObj</td> |
+ <td>Object received from <code>findDevice()</code> callback.</td> |
+ </tr> |
+ <tr> |
+ <td>transferInfo</td> |
+ <td>Parameter object with values from the table below. |
+ Check your USB device protocol specification |
+ to know which values are supported.</td> |
+ </tr> |
+ <tr> |
+ <td>transferCallback()</td> |
+ <td>Invoked when the transfer has completed. |
+ Please note this only indicates that |
+ the transfer has been processed. |
+ The device's response, if any, will always be sent through |
+ the <code>onEvent()</code> callback set on <code>findDevice()</code>. |
+ </td> |
+ </tr> |
+</table> |
+<p> |
+Values for <code>transferInfo</code> object: |
+</p> |
+<table border="0"> |
+ <tr> |
+ <th scope="col"> Value </th> |
+ <th scope="col"> Description </th> |
+ </tr> |
+ <tr> |
+ <td>requestType (string)</td> |
+ <td>"vendor", "standard", "class" or "reserved".</td> |
+ </tr> |
+ <tr> |
+ <td>recipient (string)</td> |
+ <td>"device", "interface", "endpoint" or "other".</td> |
+ </tr> |
+ <tr> |
+ <td>direction (string)</td> |
+ <td>in" or "out". |
+ IN direction is used to notify the device |
+ that it should send information to the host. |
+ All communication in a USB bus is host-initiated, |
+ so use an 'in' transfer to allow a device |
+ to send information back.</td> |
+ </tr> |
+ <tr> |
+ <td>request (integer)</td> |
+ <td>Defined by your device's protocol.</td> |
+ </tr> |
+ <tr> |
+ <td>value (integer)</td> |
+ <td>Defined by your device's protocol.</td> |
+ </tr> |
+ <tr> |
+ <td>index (integer)</td> |
+ <td>Defined by your device's protocol.</td> |
+ </tr> |
+ <tr> |
+ <td>length (integer)</td> |
+ <td>Only used when direction is "in". |
+ Notifies the device that this is the amount |
+ of data the host is expecting in response.</td> |
+ </tr> |
+ <tr> |
+ <td>data (integer array)</td> |
+ <td>Defined by your device's protocol, |
+ required when direction is "out". |
+ <b>WARNING: </b>in the near future, |
+ this parameter will likely change |
+ to <code>ArrayBuffer</code>.</td> |
+ </tr> |
+</table> |
+<p> |
+Example: |
+</p> |
+<pre> |
+var transferInfo = { |
+ "requestType": "vendor", |
+ "recipient": "device", |
+ "direction": "out", |
+ "request": 0x31, |
+ "value": 120, |
+ "index": 0, |
+ "data": [4, 8, 15, 16, 23, 42] |
+ }; |
+chrome.experimental.usb.controlTransfer(deviceObj, transferInfo, optionalCallback); |
+</pre> |
+<h3>Sending data - isochronous transfers</h3> |
+<p> |
+Isochronous transfers are commonly used for streams of data. |
+Video and sound, for example, are good candidates for this transfer type. |
+To send an isochronous transfer, use: |
+</p> |
+<pre> |
+chrome.experimental.usb.isochronousTransfer(deviceObj, isochronousTransferInfo, transferCallback) |
+</pre> |
+<br> |
+<table border="0"> |
+ <tr> |
+ <th scope="col"> Parameter </th> |
+ <th scope="col"> Description </th> |
+ </tr> |
+ <tr> |
+ <td>deviceObj</td> |
+ <td>Object sent on <code>findDevice()</code> callback.</td> |
+ </tr> |
+ <tr> |
+ <td>isochronousTransferInfo</td> |
+ <td>Parameter object with the values in the table below.</td> |
+ </tr> |
+ <tr> |
+ <td>transferCallback()</td> |
+ <td>Invoked when the transfer has completed. |
+ Notice that this callback doesn't represent any response from the device. |
+ It's just to notify your code that the asynchronous transfer request |
+ has been processed and you can go ahead. |
+ The device's response, if any, will always be sent through |
+ the <code>onEvent()</code> callback set on <code>findDevice()</code>. |
+ </td> |
+ </tr> |
+</table> |
+<p> |
+Values for <code>isochronousTransferInfo</code> object: |
+</p> |
+<table border="0"> |
+ <tr> |
+ <th scope="col"> Value </th> |
+ <th scope="col"> Description </th> |
+ </tr> |
+ <tr> |
+ <td>transferInfo (object)</td> |
+ <td>A parameter object with the following parameters:<br> |
+ <b>direction (string): </b>"in" or "out".<br> |
+ <b>endpoint (integer): </b>defined by your device's protocol.<br> |
+ <b>length (integer): </b>only used when direction is "in". |
+ Notifies the device that this is the amount |
+ of data the host is expecting in response<br> |
+ <b>data (integer array): </b>defined by your device's protocol; |
+ only used when direction is "out". |
+ </td> |
+ </tr> |
+ <tr> |
+ <td>packets (integer)</td> |
+ <td>Total number of packets expected in this transfer.</td> |
+ </tr> |
+ <tr> |
+ <td>packetLength (integer)</td> |
+ <td>Expected length of each packet in this transfer.</td> |
+ </tr> |
+</table> |
+<p> |
+Example: |
+</p> |
+<pre> |
+var transferInfo = { |
+ "direction": "in", |
+ "endpoint": 1, |
+ "length": 2560 |
+ }; |
+var isoTransferInfo = { |
+ "transferInfo": transferInfo, |
+ "packets": 20, |
+ "packetLength": 128 |
+}; |
+chrome.experimental.usb.isochronousTransfer(deviceObj, isoTransferInfo, optionalCallback); |
+</pre> |
+<h3>Sending data - bulk transfers</h3> |
+<p> |
+Bulk transfer is a USB transfer type commonly used |
+to transfer a large amount of data reliably. |
+The method has three parameters: |
+</p> |
+<pre> |
+chrome.experimental.usb.bulkTransfer(deviceObj, transferInfo, transferCallback) |
+</pre> |
+<br> |
+<table border="0"> |
+ <tr> |
+ <th scope="col"> Parameter </th> |
+ <th scope="col"> Description </th> |
+ </tr> |
+ <tr> |
+ <td>deviceObj</td> |
+ <td>Object sent on <code>findDevice()</code> callback.</td> |
+ </tr> |
+ <tr> |
+ <td>transferInfo</td> |
+ <td>Parameter object with the values in the table below.</td> |
+ </tr> |
+ <tr> |
+ <td>transferCallback()</td> |
+ <td>Invoked when the transfer has completed. |
+ Notice that this callback doesn't represent any response from the device. |
+ It's just to notify your code that the asynchronous transfer request |
+ has been processed and you can go ahead. |
+ The device's response, if any, will always be sent through |
+ the <code>onEvent()</code> callback set on <code>findDevice()</code>. |
+ </td> |
+ </tr> |
+</table> |
+<p> |
+Values for <code>transferInfo</code> object: |
+</p> |
+<table border="0"> |
+ <tr> |
+ <th scope="col"> Value </th> |
+ <th scope="col"> Description </th> |
+ </tr> |
+ <tr> |
+ <td>direction (string)</td> |
+ <td>"in" or "out".</td> |
+ </tr> |
+ <tr> |
+ <td>endpoint (integer)</td> |
+ <td>Defined by your device's protocol.</td> |
+ </tr> |
+ <tr> |
+ <td>length (integer)</td> |
+ <td>Only used when direction is "in". |
+ Notifies the device that this is the amount |
+ of data the host is expecting in response.</td> |
+ </tr> |
+ <tr> |
+ <td>data (integer array)</td> |
+ <td>Defined by your device's protocol; |
+ only used when direction is "out".</td> |
+ </tr> |
+</table> |
+<p> |
+Example: |
+</p> |
+<pre> |
+var transferInfo = { |
+ "direction": "out", |
+ "endpoint": 1, |
+ "data": [4, 8, 15, 16, 23, 42] |
+ }; |
+</pre> |
+<h3>Sending data - interrupt transfers</h3> |
+<p> |
+Interrupt transfers are used to send important notifications. |
+Since all USB communication is initiated by the host, |
+host code usually polls the device periodically, |
+sending interrupt IN transfers that will make the device send data back |
+if there is anything on the interrupt queue. |
+The method has three parameters: |
+</p> |
+<pre> |
+chrome.experimental.usb.interruptTransfer(deviceObj, transferInfo, transferCallback) |
+</pre> |
+<br> |
+<table border="0"> |
+ <tr> |
+ <th scope="col"> Parameter </th> |
+ <th scope="col"> Description </th> |
+ </tr> |
+ <tr> |
+ <td>deviceObj</td> |
+ <td>Object sent on <code>findDevice()</code> callback.</td> |
+ </tr> |
+ <tr> |
+ <td>transferInfo</td> |
+ <td>Parameter object with the values in the table below.</td> |
+ </tr> |
+ <tr> |
+ <td>transferCallback()</td> |
+ <td>Invoked when the transfer has completed. |
+ Notice that this callback doesn't represent any response from the device. |
+ It's just to notify your code that the asynchronous transfer request |
+ has been processed and you can go ahead. |
+ The device's response, if any, will always be sent through |
+ the <code>onEvent()</code> callback set on <code>findDevice()</code>. |
+ </td> |
+ </tr> |
+</table> |
+<p> |
+Values for <code>transferInfo</code> object: |
+</p> |
+<table border="0"> |
+ <tr> |
+ <th scope="col"> Value </th> |
+ <th scope="col"> Description </th> |
+ </tr> |
+ <tr> |
+ <td>direction (string)</td> |
+ <td>"in" or "out".</td> |
+ </tr> |
+ <tr> |
+ <td>endpoint (integer)</td> |
+ <td>Defined by your device's protocol.</td> |
+ </tr> |
+ <tr> |
+ <td>length (integer)</td> |
+ <td>Only used when direction is "in". |
+ Notifies the device that this is the amount |
+ of data the host is expecting in response.</td> |
+ </tr> |
+ <tr> |
+ <td>data (integer array)</td> |
+ <td>Defined by your device's protocol; |
+ only used when direction is "out".</td> |
+ </tr> |
+<p> |
+Example: |
+</p> |
+<pre> |
+var transferInfo = { |
+ "direction": "in", |
+ "endpoint": 1, |
+ "length": 2 |
+ }; |
+chrome.experimental.usb.interruptTransfer(deviceObj, transferInfo, optionalCallback); |
+</pre> |
+<h3>Caveats</h3> |
+<p> |
+On Linux, |
+you must have specific permission to access USB devices. |
+Create a file: <code>/etc/udev/rules.d/50-yourdevicename.rules</code>. |
+Add the following content: |
+</p> |
+<pre> |
+SUBSYSTEM=="usb", ATTR{idVendor}=="yourdevicevendor", MODE="0664", GROUP="plugdev" |
+</pre> |
+<p> |
+On MacOSX, |
+devices which expose a HID profile cannot be managed |
+using this low level API due to system restrictions. |
+Currently there is no workaround. |
+</p> |
+<h2 id="serial">Accessing serial devices</h2> |
+<p> |
+You can use the serial API to read |
+and write from a serial device. |
+</p> |
+<h3>Manifest requirement</h3> |
+<p> |
+The "serial" permission is not yet required; |
+"experimental" is enough for now: |
+</p> |
+<pre> |
+"permissions": ["experimental"] |
+</pre> |
+<h3>Listing available serial ports</h3> |
+<p> |
+To get a list of available serial ports, |
+use the <code>getPorts()</code> method: |
+</p> |
+<pre> |
+var onGetPorts = function(ports) { |
+ for (var i=0; i<ports.length; i++) { |
+ console.log(ports[i]); |
+ } |
+} |
+chrome.experimental.serial.getPorts(onGetPorts); |
+</pre> |
+<h3>Opening a serial device</h3> |
+<p> |
+Here's how to open a serial device: |
+</p> |
+<pre> |
+var onOpen = function(connectionInfo) { |
+ // The serial device has been opened. Save its id to use later. |
+ var conId = connectionInfo.connectionId; |
+ // Do whatever you need to do with the opened device. |
+} |
+// Open the serial device /dev/ttyS01 |
+chrome.experimental.serial.open("/dev/ttyS01", onOpen); |
+</pre> |
+<h3>Closing a serial device</h3> |
+<p> |
+Here's how to close a serial device: |
+</p> |
+<pre> |
+var onClose = function(result) { |
+ console.log(“Serial port closed”); |
+} |
+chrome.experimental.serial.close(conId, onClose); |
+</pre> |
+<h3>Reading from a serial device</h3> |
+<p> |
+The serial API reads from the serial port and |
+delivers the read bytes as an ArrayBuffer. |
+There is no guarantee that all the available bytes will be read in one chunk |
+(they are currently read one byte per time, but this might change in the future). |
+The following procedure can accumulate read bytes until a new line is read, |
+and then call a listener with the <code>ArrayBuffer</code> bytes converted to a String: |
+</p> |
+<pre> |
+var dataRead=''; |
+var onCharRead=function(readInfo) { |
+ if (!connectionInfo) { |
+ return; |
+ } |
+ if (readInfo && readInfo.bytesRead>0 && readInfo.data) { |
+ var str=ab2str(readInfo.data); |
+ if (str[str.length-1]==='\n') { |
+ dataRead+=str.substring(0, str.length-1); |
+ onLineRead(dataRead); |
+ dataRead=""; |
+ } else { |
+ dataRead+=str; |
+ } |
+ } |
+ chrome.experimental.serial.read(connectionInfo.connectionId, onCharRead); |
+ } |
+/* Convert an ArrayBuffer to a String, using UTF-8 as the encoding scheme. |
+ This is consistent with how Arduino sends characters by default */ |
+ var ab2str=function(buf) { |
+ return String.fromCharCode.apply(null, new Uint8Array(buf)); |
+ }; |
+</pre> |
+<h3>Writing to a serial device</h3> |
+<p> |
+The writing routine is simpler than the reading, |
+since the writing can occur all at once. |
+The only catch is that if your data protocol is String based, |
+you have to convert your output string to an <code>ArrayBuffer</code> |
+to compy with write's method signature. |
+See the code below: |
+</p> |
+<pre> |
+var writeSerial=function(str) { |
+ chrome.experimental.serial.write(connectionInfo.connectionId, str2ab(str), onWrite); |
+} |
+var str2ab=function(str) { |
+ var buf=new ArrayBuffer(str.length); |
+ var bufView=new Uint8Array(buf); |
+ for (var i=0; i<str.length; i++) { |
+ bufView[i]=str.charCodeAt(i); |
+ } |
+ return buf; |
+} |
+</pre> |
+<h3>Flushing a serial device buffer</h3> |
+<p> |
+You can flush your serial device buffer by issuing the flush command on the API: |
+</p> |
+<pre> |
+var flushSerial=function(str) { |
+ chrome.experimental.serial.flush(connectionInfo.connectionId, onFlush); |
+} |
+</pre> |
+<p class="backtotop"><a href="#top">Back to top</a></p> |