├── README.md ├── demos ├── console │ ├── console.js │ ├── hterm_all.js │ ├── index.html │ └── sketch │ │ └── sketch.ino ├── index.html ├── rgb │ ├── index.html │ ├── rgb.js │ └── sketch │ │ └── sketch.ino └── serial.js ├── hardware └── webusb │ └── avr │ ├── boards.txt │ └── platform.txt └── library └── WebUSB ├── WebUSB.cpp ├── WebUSB.h ├── keywords.txt └── library.properties /README.md: -------------------------------------------------------------------------------- 1 | WebUSB ❤ ️Arduino 2 | ================ 3 | 4 | This repository contains an Arduino library for WebUSB-enabling your sketches. 5 | Example sketches and JavaScript code are available in the demos directory. 6 | 7 | The WebUSB object is a copy of the Arduino SDK's built-in USB serial library. 8 | It creates a WebUSB-compatible vendor-specific interface rather than one marked 9 | as USB CDC-ACM. This prevents operating system drivers from claiming the device 10 | and making it inaccessible to the browser. This library also implements: 11 | 12 | * The WebUSB landing page descriptor, providing a hint to the browser about 13 | what page the user should navigate to to interact with the device. In 14 | Google Chrome the presence of this descriptor causes the browser to display 15 | a notification when the device is connected. The user can click on this 16 | notification to navigate directly to the provided URL. 17 | * Microsoft OS 2.0 Descriptors which instruct the Windows operating system 18 | (8.1 and above) to automatically the `WinUSB.sys` driver so that the browser 19 | can connect to the device. 20 | 21 | Compatible Hardware 22 | ------------------- 23 | 24 | WebUSB requires an Arduino model that gives the sketch complete control over the USB hardware. This library has been tested with the following models: 25 | 26 | * Arduino Leonardo 27 | * Arduino/Genuino Micro 28 | * Arduino/Genuino Zero 29 | * Arduino/Genuino MKR1000 30 | * Arduino MKRZero 31 | * Arduino MKR FOX 1200 32 | * Arduino MKR WAN 1300 33 | * Arduino MKR GSM 1400 34 | * Arduino MKR NB 1500 35 | * Arduino MKR WiFi 1010 36 | * Arduino MKR Vidor 4000 37 | * Arduino NANO 33 IoT 38 | * Adafruit Feather 32u4 39 | * Adafruit ItsyBitsy 32u4 40 | * Adafruit Feather M0 Express 41 | 42 | Getting Started 43 | --------------- 44 | 45 | 1. Install at least version 1.6.11 of the [Arduino IDE](https://www.arduino.cc/en/Main/Software). 46 | 47 | 2. The WebUSB library provides all the extra low-level USB code necessary for WebUSB support except for one thing: Your device must be upgraded from USB 2.0 to USB 2.1. To do this go into the SDK installation directory and open `hardware/arduino/avr/cores/arduino/USBCore.h`. Then find the line `#define USB_VERSION 0x200` and change `0x200` to `0x210`. That's it! 48 | 49 | **macOS:** Right click on the Arduino application icon and then click on show package contents menu item. Navigate to `Contents/Java/hardware/arduino/avr/cores/arduino/USBCore.h` 50 | 51 | **Warning:** Windows requires USB 2.1 devices to present a Binary Object Store (BOS) descriptor when they are enumerated. The code to support this is added by including the "WebUSB" library in your sketch. If you do not include this library after making this change to the SDK then Windows will no longer be able to recognize your device and you will not be able to upload new sketches to it. 52 | 53 | 3. Copy (or symlink) the `library/WebUSB` directory from this repository into the `libraries` folder in your sketchbooks directory. 54 | 55 | 4. Launch the Arduino IDE. You should see "WebUSB" as an option under "Sketch > Include Library". 56 | 57 | 5. Load up `demos/rgb/sketch/sketch.ino` and program it to your device. 58 | 59 | 6. When the sketch is finished uploading you should see a notification from Chrome: "Go to [https://webusb.github.io/arduino/demos/](https://webusb.github.io/arduino/demos/) to connect." Try it out! 60 | 61 | **Windows:** This notification is currently disabled in Chrome on Windows due to [Chromium issue 656702](https://crbug.com/656702). Implementation of new, more stable USB support for Windows is tracked on Chromium issues [422562](https://crbug.com/422562) and [637404](https://crbug.com/637404). 62 | 63 | **Android:** This notification is not supported on Android because of OS 64 | limitations that prevent the browser from connecting to a device without user 65 | interaction. 66 | 67 | Adding New Boards of Supported Architecture 68 | ------------------------------------------- 69 | 1. Plug in your board. 70 | 2. Run `lsusb` and find your boards _vendor ID_ and _product ID_ 71 | Example: `Bus 001 Device 119: ID 2341:805a Arduino SA` where 0x2341 is _vendor ID_ and 0x805a is _product ID_. 72 | 3. Add your board's _vendor ID_ and _product ID_ to the `filters` in `serial.js` file - 73 | ``` 74 | const filters = [ 75 | { 'vendorId': 0x2341, 'productId': 0x8036 }, // Arduino Leonardo 76 | { 'vendorId': 0x2341, 'productId': 0x8037 }, // Arduino Micro 77 | { 'vendorId': 0x2341, 'productId': 0x804d }, // Arduino/Genuino Zero 78 | { 'vendorId': 0x2341, 'productId': 0x804e }, // Arduino/Genuino MKR1000 79 | { 'vendorId': 0x2341, 'productId': 0x804f }, // Arduino MKRZERO 80 | { 'vendorId': 0x2341, 'productId': 0x8050 }, // Arduino MKR FOX 1200 81 | { 'vendorId': 0x2341, 'productId': 0x8052 }, // Arduino MKR GSM 1400 82 | { 'vendorId': 0x2341, 'productId': 0x8053 }, // Arduino MKR WAN 1300 83 | { 'vendorId': 0x2341, 'productId': 0x8054 }, // Arduino MKR WiFi 1010 84 | { 'vendorId': 0x2341, 'productId': 0x8055 }, // Arduino MKR NB 1500 85 | { 'vendorId': 0x2341, 'productId': 0x8056 }, // Arduino MKR Vidor 4000 86 | { 'vendorId': 0x2341, 'productId': 0x8057 }, // Arduino NANO 33 IoT 87 | { 'vendorId': 0x239A, 'productId': 0x000E }, // Adafruit ItsyBitsy 32u4 88 | { 'vendorId': 0x239A, 'productId': 0x800D }, // Adafruit ItsyBitsy 32u4 89 | ]; 90 | ``` 91 | 4. Try connecting ! 92 | 93 | OR 94 | 95 | 1. Connect your board 96 | 2. Load the sketch onto your board 97 | 3. Open the landing URL 98 | 4. Inspect the page and goto _Sources_ 99 | 5. Open `serial.js` in the inspector and add your _vendor ID_ and _product ID_ and don't forget to save - press `Ctrl+S` 100 | 6. Press Connect and hopefully it works! -------------------------------------------------------------------------------- /demos/console/console.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | hterm.defaultStorage = new lib.Storage.Local(); 5 | 6 | var port; 7 | 8 | let textEncoder = new TextEncoder(); 9 | 10 | let t = new hterm.Terminal(); 11 | t.onTerminalReady = () => { 12 | console.log('Terminal ready.'); 13 | let io = t.io.push(); 14 | 15 | io.onVTKeystroke = str => { 16 | if (port !== undefined) { 17 | port.send(textEncoder.encode(str)).catch(error => { 18 | t.io.println('Send error: ' + error); 19 | }); 20 | } 21 | }; 22 | 23 | io.sendString = str => { 24 | if (port !== undefined) { 25 | port.send(textEncoder.encode(str)).catch(error => { 26 | t.io.println('Send error: ' + error); 27 | }); 28 | } 29 | }; 30 | }; 31 | 32 | document.addEventListener('DOMContentLoaded', event => { 33 | let connectButton = document.querySelector('#connect'); 34 | 35 | t.decorate(document.querySelector('#terminal')); 36 | t.setWidth(80); 37 | t.setHeight(24); 38 | t.installKeyboard(); 39 | 40 | function connect() { 41 | t.io.println('Connecting to ' + port.device_.productName + '...'); 42 | port.connect().then(() => { 43 | console.log(port); 44 | t.io.println('Connected.'); 45 | connectButton.textContent = 'Disconnect'; 46 | port.onReceive = data => { 47 | let textDecoder = new TextDecoder(); 48 | t.io.print(textDecoder.decode(data)); 49 | } 50 | port.onReceiveError = error => { 51 | t.io.println('Receive error: ' + error); 52 | }; 53 | }, error => { 54 | t.io.println('Connection error: ' + error); 55 | }); 56 | }; 57 | 58 | connectButton.addEventListener('click', function() { 59 | if (port) { 60 | port.disconnect(); 61 | connectButton.textContent = 'Connect'; 62 | port = null; 63 | } else { 64 | serial.requestPort().then(selectedPort => { 65 | port = selectedPort; 66 | connect(); 67 | }).catch(error => { 68 | t.io.println('Connection error: ' + error); 69 | }); 70 | } 71 | }); 72 | 73 | serial.getPorts().then(ports => { 74 | if (ports.length == 0) { 75 | t.io.println('No devices found.'); 76 | } else { 77 | port = ports[0]; 78 | connect(); 79 | } 80 | }); 81 | }); 82 | })(); 83 | -------------------------------------------------------------------------------- /demos/console/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Console 7 | 8 | 9 | 10 | 11 | 12 |

13 | 14 |

15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /demos/console/sketch/sketch.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /** 4 | * Creating an instance of WebUSBSerial will add an additional USB interface to 5 | * the device that is marked as vendor-specific (rather than USB CDC-ACM) and 6 | * is therefore accessible to the browser. 7 | * 8 | * The URL here provides a hint to the browser about what page the user should 9 | * navigate to to interact with the device. 10 | */ 11 | WebUSB WebUSBSerial(1 /* https:// */, "webusb.github.io/arduino/demos/console"); 12 | 13 | #define Serial WebUSBSerial 14 | 15 | const int ledPin = 13; 16 | 17 | void setup() { 18 | while (!Serial) { 19 | ; 20 | } 21 | Serial.begin(9600); 22 | Serial.write("Sketch begins.\r\n> "); 23 | Serial.flush(); 24 | pinMode(ledPin, OUTPUT); 25 | } 26 | 27 | void loop() { 28 | if (Serial && Serial.available()) { 29 | int byte = Serial.read(); 30 | Serial.write(byte); 31 | if (byte == 'H') { 32 | Serial.write("\r\nTurning LED on."); 33 | digitalWrite(ledPin, HIGH); 34 | } else if (byte == 'L') { 35 | Serial.write("\r\nTurning LED off."); 36 | digitalWrite(ledPin, LOW); 37 | } 38 | Serial.write("\r\n> "); 39 | Serial.flush(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /demos/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WebUSB Demos 5 | 6 | 7 |

WebUSB Demos

8 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /demos/rgb/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | RGB LED 7 | 8 | 9 | 10 | 11 |

12 | 13 |

14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /demos/rgb/rgb.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | document.addEventListener('DOMContentLoaded', event => { 5 | let connectButton = document.querySelector("#connect"); 6 | let statusDisplay = document.querySelector('#status'); 7 | let redSlider = document.querySelector('#red'); 8 | let greenSlider = document.querySelector('#green'); 9 | let blueSlider = document.querySelector('#blue'); 10 | let port; 11 | 12 | function connect() { 13 | port.connect().then(() => { 14 | statusDisplay.textContent = ''; 15 | connectButton.textContent = 'Disconnect'; 16 | 17 | port.onReceive = data => { 18 | let textDecoder = new TextDecoder(); 19 | console.log(textDecoder.decode(data)); 20 | } 21 | port.onReceiveError = error => { 22 | console.error(error); 23 | }; 24 | }, error => { 25 | statusDisplay.textContent = error; 26 | }); 27 | } 28 | 29 | function onUpdate() { 30 | if (!port) { 31 | return; 32 | } 33 | 34 | let view = new Uint8Array(3); 35 | view[0] = parseInt(redSlider.value); 36 | view[1] = parseInt(greenSlider.value); 37 | view[2] = parseInt(blueSlider.value); 38 | port.send(view); 39 | }; 40 | 41 | redSlider.addEventListener('input', onUpdate); 42 | greenSlider.addEventListener('input', onUpdate); 43 | blueSlider.addEventListener('input', onUpdate); 44 | 45 | connectButton.addEventListener('click', function() { 46 | if (port) { 47 | port.disconnect(); 48 | connectButton.textContent = 'Connect'; 49 | statusDisplay.textContent = ''; 50 | port = null; 51 | } else { 52 | serial.requestPort().then(selectedPort => { 53 | port = selectedPort; 54 | connect(); 55 | }).catch(error => { 56 | statusDisplay.textContent = error; 57 | }); 58 | } 59 | }); 60 | 61 | serial.getPorts().then(ports => { 62 | if (ports.length == 0) { 63 | statusDisplay.textContent = 'No device found.'; 64 | } else { 65 | statusDisplay.textContent = 'Connecting...'; 66 | port = ports[0]; 67 | connect(); 68 | } 69 | }); 70 | }); 71 | })(); 72 | -------------------------------------------------------------------------------- /demos/rgb/sketch/sketch.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /** 4 | * Creating an instance of WebUSBSerial will add an additional USB interface to 5 | * the device that is marked as vendor-specific (rather than USB CDC-ACM) and 6 | * is therefore accessible to the browser. 7 | * 8 | * The URL here provides a hint to the browser about what page the user should 9 | * navigate to to interact with the device. 10 | */ 11 | WebUSB WebUSBSerial(1 /* https:// */, "webusb.github.io/arduino/demos/rgb"); 12 | 13 | #define Serial WebUSBSerial 14 | 15 | const int redPin = 9; 16 | const int greenPin = 10; 17 | const int bluePin = 11; 18 | int color[3]; 19 | int colorIndex; 20 | 21 | void setup() { 22 | while (!Serial) { 23 | ; 24 | } 25 | Serial.begin(9600); 26 | Serial.write("Sketch begins.\r\n"); 27 | Serial.flush(); 28 | colorIndex = 0; 29 | } 30 | 31 | void loop() { 32 | if (Serial && Serial.available()) { 33 | color[colorIndex++] = Serial.read(); 34 | if (colorIndex == 3) { 35 | analogWrite(redPin, color[0]); 36 | analogWrite(greenPin, color[1]); 37 | analogWrite(bluePin, color[2]); 38 | Serial.print("Set LED to "); 39 | Serial.print(color[0]); 40 | Serial.print(", "); 41 | Serial.print(color[1]); 42 | Serial.print(", "); 43 | Serial.print(color[2]); 44 | Serial.print(".\r\n"); 45 | Serial.flush(); 46 | colorIndex = 0; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /demos/serial.js: -------------------------------------------------------------------------------- 1 | var serial = {}; 2 | 3 | (function() { 4 | 'use strict'; 5 | 6 | serial.getPorts = function() { 7 | return navigator.usb.getDevices().then(devices => { 8 | return devices.map(device => new serial.Port(device)); 9 | }); 10 | }; 11 | 12 | serial.requestPort = function() { 13 | const filters = [ 14 | { 'vendorId': 0x2341, 'productId': 0x8036 }, // Arduino Leonardo 15 | { 'vendorId': 0x2341, 'productId': 0x8037 }, // Arduino Micro 16 | { 'vendorId': 0x2341, 'productId': 0x804d }, // Arduino/Genuino Zero 17 | { 'vendorId': 0x2341, 'productId': 0x804e }, // Arduino/Genuino MKR1000 18 | { 'vendorId': 0x2341, 'productId': 0x804f }, // Arduino MKRZERO 19 | { 'vendorId': 0x2341, 'productId': 0x8050 }, // Arduino MKR FOX 1200 20 | { 'vendorId': 0x2341, 'productId': 0x8052 }, // Arduino MKR GSM 1400 21 | { 'vendorId': 0x2341, 'productId': 0x8053 }, // Arduino MKR WAN 1300 22 | { 'vendorId': 0x2341, 'productId': 0x8054 }, // Arduino MKR WiFi 1010 23 | { 'vendorId': 0x2341, 'productId': 0x8055 }, // Arduino MKR NB 1500 24 | { 'vendorId': 0x2341, 'productId': 0x8056 }, // Arduino MKR Vidor 4000 25 | { 'vendorId': 0x2341, 'productId': 0x8057 }, // Arduino NANO 33 IoT 26 | { 'vendorId': 0x239A }, // Adafruit Boards! 27 | ]; 28 | return navigator.usb.requestDevice({ 'filters': filters }).then( 29 | device => new serial.Port(device) 30 | ); 31 | } 32 | 33 | serial.Port = function(device) { 34 | this.device_ = device; 35 | this.interfaceNumber_ = 2; // original interface number of WebUSB Arduino demo 36 | this.endpointIn_ = 5; // original in endpoint ID of WebUSB Arduino demo 37 | this.endpointOut_ = 4; // original out endpoint ID of WebUSB Arduino demo 38 | }; 39 | 40 | serial.Port.prototype.connect = function() { 41 | let readLoop = () => { 42 | this.device_.transferIn(this.endpointIn_, 64).then(result => { 43 | this.onReceive(result.data); 44 | readLoop(); 45 | }, error => { 46 | this.onReceiveError(error); 47 | }); 48 | }; 49 | 50 | return this.device_.open() 51 | .then(() => { 52 | if (this.device_.configuration === null) { 53 | return this.device_.selectConfiguration(1); 54 | } 55 | }) 56 | .then(() => { 57 | var configurationInterfaces = this.device_.configuration.interfaces; 58 | configurationInterfaces.forEach(element => { 59 | element.alternates.forEach(elementalt => { 60 | if (elementalt.interfaceClass==0xff) { 61 | this.interfaceNumber_ = element.interfaceNumber; 62 | elementalt.endpoints.forEach(elementendpoint => { 63 | if (elementendpoint.direction == "out") { 64 | this.endpointOut_ = elementendpoint.endpointNumber; 65 | } 66 | if (elementendpoint.direction=="in") { 67 | this.endpointIn_ =elementendpoint.endpointNumber; 68 | } 69 | }) 70 | } 71 | }) 72 | }) 73 | }) 74 | .then(() => this.device_.claimInterface(this.interfaceNumber_)) 75 | .then(() => this.device_.selectAlternateInterface(this.interfaceNumber_, 0)) 76 | // The vendor-specific interface provided by a device using this 77 | // Arduino library is a copy of the normal Arduino USB CDC-ACM 78 | // interface implementation and so reuses some requests defined by 79 | // that specification. This request sets the DTR (data terminal 80 | // ready) signal high to indicate to the device that the host is 81 | // ready to send and receive data. 82 | .then(() => this.device_.controlTransferOut({ 83 | 'requestType': 'class', 84 | 'recipient': 'interface', 85 | 'request': 0x22, 86 | 'value': 0x01, 87 | 'index': this.interfaceNumber_})) 88 | .then(() => { 89 | readLoop(); 90 | }); 91 | }; 92 | 93 | serial.Port.prototype.disconnect = function() { 94 | // This request sets the DTR (data terminal ready) signal low to 95 | // indicate to the device that the host has disconnected. 96 | return this.device_.controlTransferOut({ 97 | 'requestType': 'class', 98 | 'recipient': 'interface', 99 | 'request': 0x22, 100 | 'value': 0x00, 101 | 'index': this.interfaceNumber_}) 102 | .then(() => this.device_.close()); 103 | }; 104 | 105 | serial.Port.prototype.send = function(data) { 106 | return this.device_.transferOut(this.endpointOut_, data); 107 | }; 108 | })(); 109 | -------------------------------------------------------------------------------- /hardware/webusb/avr/boards.txt: -------------------------------------------------------------------------------- 1 | microwebusb.name=Arduino Micro (WebUSB) 2 | 3 | microwebusb.upload.tool=arduino:avrdude 4 | microwebusb.upload.protocol=avr109 5 | microwebusb.upload.maximum_size=28672 6 | microwebusb.upload.maximum_data_size=2560 7 | microwebusb.upload.speed=57600 8 | microwebusb.upload.disable_flushing=true 9 | microwebusb.upload.use_1200bps_touch=true 10 | microwebusb.upload.wait_for_upload_port=true 11 | 12 | microwebusb.bootloader.tool=arduino:avrdude 13 | microwebusb.bootloader.low_fuses=0xff 14 | microwebusb.bootloader.high_fuses=0xd8 15 | microwebusb.bootloader.extended_fuses=0xcb 16 | microwebusb.bootloader.file=caterina/Caterina2-Micro-WebUSB.hex 17 | microwebusb.bootloader.unlock_bits=0x3F 18 | microwebusb.bootloader.lock_bits=0x2F 19 | 20 | microwebusb.build.mcu=atmega32u4 21 | microwebusb.build.f_cpu=16000000L 22 | microwebusb.build.vid=0x2341 23 | microwebusb.build.pid=0x8037 24 | microwebusb.build.usb_product="Arduino Micro WebUSB" 25 | microwebusb.build.board=AVR_MICRO 26 | microwebusb.build.core=arduino:arduino 27 | microwebusb.build.variant=arduino:micro 28 | microwebusb.build.extra_flags={build.usb_flags} "-DUSB_VERSION=0x210" 29 | 30 | leowebusb.name=Arduino Leonardo (WebUSB) 31 | 32 | leowebusb.upload.tool=arduino:avrdude 33 | leowebusb.upload.protocol=avr109 34 | leowebusb.upload.maximum_size=28672 35 | leowebusb.upload.maximum_data_size=2560 36 | leowebusb.upload.speed=57600 37 | leowebusb.upload.disable_flushing=true 38 | leowebusb.upload.use_1200bps_touch=true 39 | leowebusb.upload.wait_for_upload_port=true 40 | 41 | leowebusb.bootloader.tool=arduino:avrdude 42 | leowebusb.bootloader.low_fuses=0xff 43 | leowebusb.bootloader.high_fuses=0xd8 44 | leowebusb.bootloader.extended_fuses=0xcb 45 | leowebusb.bootloader.file=caterina/Caterina2-Leonardo-WebUSB.hex 46 | leowebusb.bootloader.unlock_bits=0x3F 47 | leowebusb.bootloader.lock_bits=0x2F 48 | 49 | leowebusb.build.mcu=atmega32u4 50 | leowebusb.build.f_cpu=16000000L 51 | leowebusb.build.vid=0x2341 52 | leowebusb.build.pid=0x8036 53 | leowebusb.build.usb_product="Arduino Leonardo WebUSB" 54 | leowebusb.build.board=AVR_LEONARDO 55 | leowebusb.build.core=arduino:arduino 56 | leowebusb.build.variant=arduino:leonardo 57 | leowebusb.build.extra_flags={build.usb_flags} "-DUSB_VERSION=0x210" 58 | 59 | -------------------------------------------------------------------------------- /hardware/webusb/avr/platform.txt: -------------------------------------------------------------------------------- 1 | name=Arduino AVR Boards (WebUSB version) 2 | version=1.0.0 3 | 4 | -------------------------------------------------------------------------------- /library/WebUSB/WebUSB.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Arduino LLC 3 | Original code (pre-library): Copyright (c) 2011, Peter Barrett 4 | 5 | Permission to use, copy, modify, and/or distribute this software for 6 | any purpose with or without fee is hereby granted, provided that the 7 | above copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 12 | BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES 13 | OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 14 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 15 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 16 | SOFTWARE. 17 | */ 18 | 19 | #define MS_OS_20_SET_HEADER_DESCRIPTOR 0x00 20 | #define MS_OS_20_SUBSET_HEADER_CONFIGURATION 0x01 21 | #define MS_OS_20_SUBSET_HEADER_FUNCTION 0x02 22 | #define MS_OS_20_FEATURE_COMPATIBLE_ID 0x03 23 | #define MS_OS_20_FEATURE_REG_PROPERTY 0x04 24 | #define MS_OS_20_DESCRIPTOR_LENGTH 0xb2 25 | 26 | #include "WebUSB.h" 27 | 28 | #ifdef ARDUINO_ARCH_SAMD 29 | 30 | #define USB_SendControl USBDevice.sendControl 31 | #define USB_RecvControl USBDevice.recvControl 32 | #define USB_Available USBDevice.available 33 | #define USB_Recv USBDevice.recv 34 | #define USB_Send USBDevice.send 35 | #define USB_SendSpace(ep) (EPX_SIZE - 1) 36 | #define USB_Flush USBDevice.flush 37 | 38 | #define TRANSFER_PGM 0 39 | 40 | #define EP_TYPE_BULK_IN_WEBUSB USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0); 41 | #define EP_TYPE_BULK_OUT_WEBUSB USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_OUT(0); 42 | 43 | #else 44 | 45 | #define EP_TYPE_BULK_IN_WEBUSB EP_TYPE_BULK_IN 46 | #define EP_TYPE_BULK_OUT_WEBUSB EP_TYPE_BULK_OUT 47 | 48 | #endif 49 | 50 | const uint8_t BOS_DESCRIPTOR_PREFIX[] PROGMEM = { 51 | 0x05, // Length 52 | 0x0F, // Binary Object Store descriptor 53 | 0x39, 0x00, // Total length 54 | 0x02, // Number of device capabilities 55 | 56 | // WebUSB Platform Capability descriptor (bVendorCode == 0x01). 57 | 0x18, // Length 58 | 0x10, // Device Capability descriptor 59 | 0x05, // Platform Capability descriptor 60 | 0x00, // Reserved 61 | 0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, 62 | 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65, // WebUSB GUID 63 | 0x00, 0x01, // Version 1.0 64 | 0x01, // Vendor request code 65 | }; 66 | 67 | // Landing page (1 byte) sent in the middle. 68 | 69 | const uint8_t BOS_DESCRIPTOR_SUFFIX[] PROGMEM { 70 | // Microsoft OS 2.0 Platform Capability Descriptor (MS_VendorCode == 0x02) 71 | 0x1C, // Length 72 | 0x10, // Device Capability descriptor 73 | 0x05, // Platform Capability descriptor 74 | 0x00, // Reserved 75 | 0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, 76 | 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F, // MS OS 2.0 GUID 77 | 0x00, 0x00, 0x03, 0x06, // Windows version 78 | MS_OS_20_DESCRIPTOR_LENGTH, 0x00, // Descriptor set length 79 | 0x02, // Vendor request code 80 | 0x00 // Alternate enumeration code 81 | }; 82 | 83 | const uint8_t MS_OS_20_DESCRIPTOR_PREFIX[] PROGMEM = { 84 | // Microsoft OS 2.0 descriptor set header (table 10) 85 | 0x0A, 0x00, // Descriptor size (10 bytes) 86 | MS_OS_20_SET_HEADER_DESCRIPTOR, 0x00, // MS OS 2.0 descriptor set header 87 | 0x00, 0x00, 0x03, 0x06, // Windows version (8.1) (0x06030000) 88 | MS_OS_20_DESCRIPTOR_LENGTH, 0x00, // Size, MS OS 2.0 descriptor set 89 | 90 | // Microsoft OS 2.0 configuration subset header 91 | 0x08, 0x00, // Descriptor size (8 bytes) 92 | MS_OS_20_SUBSET_HEADER_CONFIGURATION, 0x00, // MS OS 2.0 configuration subset header 93 | 0x00, // bConfigurationValue 94 | 0x00, // Reserved 95 | 0xA8, 0x00, // Size, MS OS 2.0 configuration subset 96 | 97 | // Microsoft OS 2.0 function subset header 98 | 0x08, 0x00, // Descriptor size (8 bytes) 99 | MS_OS_20_SUBSET_HEADER_FUNCTION, 0x00, // MS OS 2.0 function subset header 100 | }; 101 | 102 | // First interface number (1 byte) sent here. 103 | 104 | const uint8_t MS_OS_20_DESCRIPTOR_SUFFIX[] PROGMEM = { 105 | 0x00, // Reserved 106 | 0xA0, 0x00, // Size, MS OS 2.0 function subset 107 | 108 | // Microsoft OS 2.0 compatible ID descriptor (table 13) 109 | 0x14, 0x00, // wLength 110 | MS_OS_20_FEATURE_COMPATIBLE_ID, 0x00, // MS_OS_20_FEATURE_COMPATIBLE_ID 111 | 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, 112 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 113 | }; 114 | 115 | 116 | const uint8_t MS_OS_20_CUSTOM_PROPERTY[] PROGMEM = { 117 | 0x84, 0x00, //wLength: 118 | MS_OS_20_FEATURE_REG_PROPERTY, 0x00, // wDescriptorType: MS_OS_20_FEATURE_REG_PROPERTY: 0x04 (Table 9) 119 | 0x07, 0x00, //wPropertyDataType: REG_MULTI_SZ (Table 15) 120 | 0x2a, 0x00, //wPropertyNameLength: 121 | //bPropertyName: “DeviceInterfaceGUID” 122 | 'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00, 123 | 'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 124 | 0x00, 0x00, 125 | 0x50, 0x00, // wPropertyDataLength 126 | //bPropertyData: “{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}”. 127 | '{', 0x00, '9', 0x00, '7', 0x00, '5', 0x00, 'F', 0x00, '4', 0x00, '4', 0x00, 'D', 0x00, '9', 0x00, '-', 0x00, 128 | '0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00, '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00, 129 | '8', 0x00, 'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00, 'C', 0x00, 'A', 0x00, 130 | '8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00, '9', 0x00, 'D', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00 131 | }; 132 | 133 | typedef struct 134 | { 135 | uint32_t dwDTERate; 136 | uint8_t bCharFormat; 137 | uint8_t bParityType; 138 | uint8_t bDataBits; 139 | uint8_t lineState; 140 | } LineInfo; 141 | 142 | static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 }; 143 | static volatile int32_t breakValue = -1; 144 | 145 | int WebUSB::getInterface(uint8_t* interfaceCount) 146 | { 147 | *interfaceCount += 1; // uses 1 interface 148 | WebUSBDescriptor webUSBInterface = { 149 | D_INTERFACE(pluggedInterface, 2, 0xff, 0, 0), 150 | D_ENDPOINT(USB_ENDPOINT_OUT(pluggedEndpoint),USB_ENDPOINT_TYPE_BULK,0x40,0), 151 | D_ENDPOINT(USB_ENDPOINT_IN (pluggedEndpoint+1),USB_ENDPOINT_TYPE_BULK,0x40,0) 152 | }; 153 | return USB_SendControl(0, &webUSBInterface, sizeof(webUSBInterface)); 154 | } 155 | 156 | int WebUSB::getDescriptor(USBSetup& setup) 157 | { 158 | if (USB_BOS_DESCRIPTOR_TYPE == setup.wValueH) 159 | { 160 | if (setup.wValueL == 0 && setup.wIndex == 0) { 161 | if (USB_SendControl(TRANSFER_PGM, &BOS_DESCRIPTOR_PREFIX, sizeof(BOS_DESCRIPTOR_PREFIX)) < 0) 162 | return -1; 163 | uint8_t landingPage = landingPageUrl ? 1 : 0; 164 | if (USB_SendControl(0, &landingPage, 1) < 0) 165 | return -1; 166 | if (USB_SendControl(TRANSFER_PGM, &BOS_DESCRIPTOR_SUFFIX, sizeof(BOS_DESCRIPTOR_SUFFIX)) < 0) 167 | return -1; 168 | return sizeof(BOS_DESCRIPTOR_PREFIX) + 1 + sizeof(BOS_DESCRIPTOR_SUFFIX); 169 | } 170 | } 171 | return 0; 172 | } 173 | 174 | uint8_t WebUSB::getShortName(char* name) 175 | { 176 | uint8_t len = strlen(shortName); 177 | memcpy(name, shortName, len); 178 | return len; 179 | } 180 | 181 | bool WebUSB::VendorControlRequest(USBSetup& setup) 182 | { 183 | if (setup.bmRequestType == (REQUEST_DEVICETOHOST | REQUEST_VENDOR | REQUEST_DEVICE)) { 184 | if (setup.bRequest == 0x01 && setup.wIndex == WEBUSB_REQUEST_GET_URL && landingPageUrl) 185 | { 186 | if (setup.wValueL != 1) 187 | return false; 188 | uint8_t urlLength = strlen(landingPageUrl); 189 | uint8_t descriptorLength = urlLength + 3; 190 | if (USB_SendControl(0, &descriptorLength, 1) < 0) 191 | return false; 192 | uint8_t descriptorType = 3; 193 | if (USB_SendControl(0, &descriptorType, 1) < 0) 194 | return false; 195 | if (USB_SendControl(0, &landingPageScheme, 1) < 0) 196 | return false; 197 | return USB_SendControl(0, landingPageUrl, urlLength) >= 0; 198 | } 199 | else if (setup.bRequest == 0x02 && setup.wIndex == MS_OS_20_REQUEST_DESCRIPTOR) 200 | { 201 | if (USB_SendControl(TRANSFER_PGM, &MS_OS_20_DESCRIPTOR_PREFIX, sizeof(MS_OS_20_DESCRIPTOR_PREFIX)) < 0) 202 | return false; 203 | if (USB_SendControl(0, &pluggedInterface, 1) < 0) 204 | return false; 205 | if (USB_SendControl(TRANSFER_PGM, &MS_OS_20_DESCRIPTOR_SUFFIX, sizeof(MS_OS_20_DESCRIPTOR_SUFFIX)) < 0) 206 | return false; 207 | if (USB_SendControl(TRANSFER_PGM, &MS_OS_20_CUSTOM_PROPERTY, sizeof(MS_OS_20_CUSTOM_PROPERTY)) < 0) 208 | return false; 209 | return true; 210 | } 211 | } 212 | return false; 213 | } 214 | 215 | 216 | bool WebUSB::setup(USBSetup& setup) 217 | { 218 | uint8_t r = setup.bRequest; 219 | uint8_t requestType = setup.bmRequestType; 220 | 221 | if (REQUEST_CLASS == (requestType & REQUEST_TYPE) && (pluggedInterface == setup.wIndex)) { 222 | if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) 223 | { 224 | if (CDC_GET_LINE_CODING == r) 225 | { 226 | return USB_SendControl(0,(void*)&_usbLineInfo,7) >= 0; 227 | } 228 | } 229 | 230 | if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) 231 | { 232 | if (CDC_SEND_BREAK == r) 233 | { 234 | breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL; 235 | } 236 | 237 | if (CDC_SET_LINE_CODING == r) 238 | { 239 | USB_RecvControl((void*)&_usbLineInfo,7); 240 | } 241 | 242 | if (CDC_SET_CONTROL_LINE_STATE == r) 243 | { 244 | _usbLineInfo.lineState = setup.wValueL; 245 | } 246 | return true; 247 | } 248 | } else if (REQUEST_VENDOR == (requestType & REQUEST_TYPE)) { 249 | return VendorControlRequest(setup); 250 | } 251 | return false; 252 | } 253 | 254 | WebUSB::WebUSB(uint8_t landingPageScheme, const char* landingPageUrl) 255 | : PluggableUSBModule(2, 1, epType), 256 | landingPageScheme(landingPageScheme), landingPageUrl(landingPageUrl), 257 | shortName(WEBUSB_SHORT_NAME) 258 | { 259 | // one interface, 2 endpoints 260 | epType[0] = EP_TYPE_BULK_OUT_WEBUSB; 261 | epType[1] = EP_TYPE_BULK_IN_WEBUSB; 262 | PluggableUSB().plug(this); 263 | } 264 | 265 | void WebUSB::begin(unsigned long /* baud_count */) 266 | { 267 | peek_buffer = -1; 268 | } 269 | 270 | void WebUSB::begin(unsigned long /* baud_count */, byte /* config */) 271 | { 272 | peek_buffer = -1; 273 | } 274 | 275 | void WebUSB::end(void) 276 | { 277 | } 278 | 279 | void WebUSB::setShortName(const char* name) 280 | { 281 | shortName = name; 282 | } 283 | 284 | int WebUSB::available(void) 285 | { 286 | if (peek_buffer >= 0) { 287 | return 1 + USB_Available(pluggedEndpoint); 288 | } 289 | return USB_Available(pluggedEndpoint); 290 | } 291 | 292 | int WebUSB::peek(void) 293 | { 294 | if (peek_buffer < 0) 295 | peek_buffer = USB_Recv(pluggedEndpoint); 296 | return peek_buffer; 297 | } 298 | 299 | int WebUSB::read(void) 300 | { 301 | if (peek_buffer >= 0) { 302 | int c = peek_buffer; 303 | peek_buffer = -1; 304 | return c; 305 | } 306 | return USB_Recv(pluggedEndpoint); 307 | } 308 | 309 | int WebUSB::availableForWrite(void) 310 | { 311 | return USB_SendSpace(pluggedEndpoint+1); 312 | } 313 | 314 | void WebUSB::flush(void) 315 | { 316 | USB_Flush(pluggedEndpoint+1); 317 | } 318 | 319 | size_t WebUSB::write(uint8_t c) 320 | { 321 | return write(&c, 1); 322 | } 323 | 324 | size_t WebUSB::write(const uint8_t *buffer, size_t size) 325 | { 326 | /* only try to send bytes if the high-level CDC connection itself 327 | is open (not just the pipe) - the OS should set lineState when the port 328 | is opened and clear lineState when the port is closed. 329 | bytes sent before the user opens the connection or after 330 | the connection is closed are lost - just like with a UART. */ 331 | 332 | // TODO - ZE - check behavior on different OSes and test what happens if an 333 | // open connection isn't broken cleanly (cable is yanked out, host dies 334 | // or locks up, or host virtual serial port hangs) 335 | if (this) { 336 | int r = USB_Send(pluggedEndpoint+1,buffer,size); 337 | if (r > 0) { 338 | return r; 339 | } else { 340 | setWriteError(); 341 | return 0; 342 | } 343 | } 344 | setWriteError(); 345 | return 0; 346 | } 347 | 348 | // This operator is a convenient way for a sketch to check whether the 349 | // port has actually been configured and opened by the host (as opposed 350 | // to just being connected to the host). It can be used, for example, in 351 | // setup() before printing to ensure that an application on the host is 352 | // actually ready to receive and display the data. 353 | // We add a short delay before returning to fix a bug observed by Federico 354 | // where the port is configured (lineState != 0) but not quite opened. 355 | WebUSB::operator bool() { 356 | if (_usbLineInfo.lineState > 0) { 357 | if (!portOpenResult){ 358 | if (portOpenPrevLineState == 0) { 359 | portOpenLineStateChangeMillis = millis(); 360 | } else { 361 | if (millis()-portOpenLineStateChangeMillis>=10){ 362 | portOpenResult = true; 363 | } 364 | } 365 | } 366 | } else { 367 | portOpenResult=false; 368 | } 369 | portOpenPrevLineState = _usbLineInfo.lineState; 370 | return portOpenResult; 371 | } 372 | 373 | unsigned long WebUSB::baud() { 374 | // Disable interrupts while reading a multi-byte value 375 | uint32_t baudrate; 376 | #ifdef ARDUINO_ARCH_SAMD 377 | // nothing needed 378 | #else 379 | // Disable IRQs while reading and clearing breakValue to make 380 | // sure we don't overwrite a value just set by the ISR. 381 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 382 | #endif 383 | baudrate = _usbLineInfo.dwDTERate; 384 | #ifdef ARDUINO_ARCH_SAMD 385 | // nothing needed 386 | #else 387 | } 388 | #endif 389 | return baudrate; 390 | } 391 | 392 | uint8_t WebUSB::stopbits() { 393 | return _usbLineInfo.bCharFormat; 394 | } 395 | 396 | uint8_t WebUSB::paritytype() { 397 | return _usbLineInfo.bParityType; 398 | } 399 | 400 | uint8_t WebUSB::numbits() { 401 | return _usbLineInfo.bDataBits; 402 | } 403 | 404 | bool WebUSB::dtr() { 405 | return _usbLineInfo.lineState & 0x1; 406 | } 407 | 408 | bool WebUSB::rts() { 409 | return _usbLineInfo.lineState & 0x2; 410 | } 411 | 412 | int32_t WebUSB::readBreak() { 413 | int32_t ret; 414 | #ifdef ARDUINO_ARCH_SAMD 415 | uint8_t enableInterrupts = ((__get_PRIMASK() & 0x1) == 0); 416 | 417 | // disable interrupts, 418 | // to avoid clearing a breakValue that might occur 419 | // while processing the current break value 420 | __disable_irq(); 421 | #else 422 | // Disable IRQs while reading and clearing breakValue to make 423 | // sure we don't overwrite a value just set by the ISR. 424 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 425 | #endif 426 | ret = breakValue; 427 | breakValue = -1; 428 | #ifdef ARDUINO_ARCH_SAMD 429 | if (enableInterrupts) { 430 | // re-enable the interrupts 431 | __enable_irq(); 432 | } 433 | #else 434 | } 435 | #endif 436 | return ret; 437 | } 438 | -------------------------------------------------------------------------------- /library/WebUSB/WebUSB.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Arduino LLC 3 | Original code (pre-library): Copyright (c) 2011, Peter Barrett 4 | 5 | Permission to use, copy, modify, and/or distribute this software for 6 | any purpose with or without fee is hereby granted, provided that the 7 | above copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 12 | BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES 13 | OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 14 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 15 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 16 | SOFTWARE. 17 | */ 18 | 19 | #ifndef WebUSB_h 20 | #define WebUSB_h 21 | 22 | #include 23 | #include 24 | #ifdef ARDUINO_ARCH_SAMD 25 | #ifdef ARDUINO_API_VERSION 26 | #include "api/PluggableUSB.h" 27 | #else 28 | #include "USB/PluggableUSB.h" 29 | #endif 30 | #else 31 | #include "PluggableUSB.h" 32 | #include 33 | #include 34 | #endif 35 | 36 | #ifndef USBCON 37 | #error "WebUSB requires a board that supports USB client device mode." 38 | #endif 39 | 40 | #define USB_BOS_DESCRIPTOR_TYPE 15 41 | #define WEBUSB_REQUEST_GET_URL 0x02 42 | 43 | #define MS_OS_20_REQUEST_DESCRIPTOR 0x07 44 | 45 | #ifndef WEBUSB_SHORT_NAME 46 | // Max length 20 (ISERIAL_MAX_LEN defined in USBDesc.h) 47 | #define WEBUSB_SHORT_NAME "WUART" 48 | #endif 49 | 50 | 51 | typedef struct 52 | { 53 | InterfaceDescriptor dif; 54 | EndpointDescriptor in; 55 | EndpointDescriptor out; 56 | } WebUSBDescriptor; 57 | 58 | class WebUSB : public PluggableUSBModule, public Stream 59 | { 60 | public: 61 | /* 62 | * Together |landingPageScheme| and |landingPageUrl| tell the browser 63 | * what page the user should visit in order to interact with their 64 | * device. |landingPageScheme| can have any of the following values: 65 | * 66 | * 0x00 -> "http://" 67 | * 0x01 -> "https://" 68 | * 69 | * This prefix is combined with |landingPageUrl| to produce the full 70 | * URL. 71 | */ 72 | WebUSB(uint8_t landingPageScheme, const char* landingPageUrl); 73 | void begin(unsigned long); 74 | void begin(unsigned long, uint8_t); 75 | void end(void); 76 | /* 77 | * Sets the string reported as the USB device serial number. 78 | * This should be called before |begin()|, typically in |setup()|. 79 | * |name| should be a pointer to static char array containing 80 | * a nul-terminated string containing at most 20 characters 81 | * (not counting the final nul character). 82 | */ 83 | void setShortName(const char* name); 84 | 85 | virtual int available(void); 86 | virtual int peek(void); 87 | virtual int read(void); 88 | int availableForWrite(void); 89 | virtual void flush(void); 90 | virtual size_t write(uint8_t); 91 | virtual size_t write(const uint8_t*, size_t); 92 | using Print::write; // pull in write(str) and write(buf, size) from Print 93 | operator bool(); 94 | 95 | volatile uint8_t _rx_buffer_head; 96 | volatile uint8_t _rx_buffer_tail; 97 | unsigned char _rx_buffer[SERIAL_BUFFER_SIZE]; 98 | 99 | int32_t readBreak(); 100 | 101 | uint32_t baud(); 102 | uint8_t stopbits(); 103 | uint8_t paritytype(); 104 | uint8_t numbits(); 105 | bool dtr(); 106 | bool rts(); 107 | enum { 108 | ONE_STOP_BIT = 0, 109 | ONE_AND_HALF_STOP_BIT = 1, 110 | TWO_STOP_BITS = 2, 111 | }; 112 | enum { 113 | NO_PARITY = 0, 114 | ODD_PARITY = 1, 115 | EVEN_PARITY = 2, 116 | MARK_PARITY = 3, 117 | SPACE_PARITY = 4, 118 | }; 119 | 120 | protected: 121 | // Implementation of the PluggableUSBModule 122 | int getInterface(uint8_t* interfaceCount); 123 | int getDescriptor(USBSetup& setup); 124 | bool setup(USBSetup& setup); 125 | uint8_t getShortName(char* name); 126 | 127 | private: 128 | bool VendorControlRequest(USBSetup& setup); 129 | 130 | #ifdef ARDUINO_ARCH_SAMD 131 | #ifdef ARDUINO_API_VERSION 132 | unsigned int epType[2]; 133 | #else 134 | uint32_t epType[2]; 135 | #endif 136 | #else 137 | uint8_t epType[2]; 138 | #endif 139 | uint16_t descriptorSize; 140 | uint8_t protocol; 141 | uint8_t idle; 142 | int peek_buffer; 143 | uint8_t landingPageScheme; 144 | const char* landingPageUrl; 145 | const char* shortName; 146 | 147 | bool portOpenResult; 148 | uint8_t portOpenPrevLineState; 149 | unsigned long portOpenLineStateChangeMillis; 150 | }; 151 | 152 | #endif // WebUSB_h 153 | -------------------------------------------------------------------------------- /library/WebUSB/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map HID 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | HID KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | begin KEYWORD2 15 | SendReport KEYWORD2 16 | AppendDescriptor KEYWORD2 17 | 18 | ####################################### 19 | # Constants (LITERAL1) 20 | ####################################### 21 | HID_TX LITERAL1 -------------------------------------------------------------------------------- /library/WebUSB/library.properties: -------------------------------------------------------------------------------- 1 | name=WebUSB 2 | version=1.0 3 | author=Arduino 4 | maintainer=Arduino 5 | sentence=Module for PluggableUSB infrastructure. Exposes an API for WebUSB API 6 | paragraph= 7 | category=Communication 8 | url=http://www.arduino.cc/en/Reference/HID 9 | architectures=avr,samd 10 | --------------------------------------------------------------------------------