diff options
| author | hathach <[email protected]> | 2021-08-05 14:06:08 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2021-08-05 14:06:08 +0700 |
| commit | b5d218e6845da43f693e5caa31d883de3b997f41 (patch) | |
| tree | 700d22e28fc17209d264048694aefe9beb59e521 | |
| parent | 2b521e0c101c371d1b0f36d594aa1e20642b9603 (diff) | |
add html extra for webusb example
| -rw-r--r-- | README.rst | 2 | ||||
| -rw-r--r-- | docs/conf.py | 3 | ||||
| -rw-r--r-- | docs/html_extra/examples/webusb-serial/application.css | 107 | ||||
| -rw-r--r-- | docs/html_extra/examples/webusb-serial/application.js | 90 | ||||
| -rw-r--r-- | docs/html_extra/examples/webusb-serial/index.html | 33 | ||||
| -rw-r--r-- | docs/html_extra/examples/webusb-serial/serial.js | 89 |
6 files changed, 323 insertions, 1 deletions
diff --git a/README.rst b/README.rst index 9e7c3139b..8a92c267f 100644 --- a/README.rst +++ b/README.rst @@ -122,7 +122,7 @@ in your project. .. |Build Status| image:: https://github.com/hathach/tinyusb/workflows/Build/badge.svg :target: https://github.com/hathach/tinyusb/actions .. |Documentation Status| image:: https://readthedocs.org/projects/tinyusb/badge/?version=latest - :target: https://openinput.readthedocs.io/en/latest/?badge=latest + :target: https://tinyusb.readthedocs.io/en/latest/?badge=latest .. |License| image:: https://img.shields.io/badge/license-MIT-brightgreen.svg :target: https://opensource.org/licenses/MIT diff --git a/docs/conf.py b/docs/conf.py index c7a17478f..1d05d7cb6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -39,4 +39,7 @@ html_theme_options = { 'sidebar_hide_name': True, } +# examples for webusb +html_extra_path = ['html_extra'] + todo_include_todos = True diff --git a/docs/html_extra/examples/webusb-serial/application.css b/docs/html_extra/examples/webusb-serial/application.css new file mode 100644 index 000000000..4ae0138bd --- /dev/null +++ b/docs/html_extra/examples/webusb-serial/application.css @@ -0,0 +1,107 @@ +.main-content { + width: 1440px; + margin: auto; + font-size: 14px; +} + +.connect-container { + margin: 20px 0; +} + +.container { + display: flex; +} + +.sender, .receiver { + flex: 1; +} + +.sender { + margin-right: 8px; +} + +.receiver { + margin-left: 8px; +} + +.lines-header { + height: 30px; + width: 100%; + box-sizing: border-box; + background-color: #444; + line-height: 30px; + color: white; + padding-left: 10px; +} + +.lines-body { + width: 100%; + background-color: #222; + min-height: 300px; + padding: 10px 0 20px 0; +} + +.line, .command-line { + box-sizing: border-box; + width: 100%; + color: #f1f1f1; + background-color: #222; + outline: none; + border: none; + padding: 5px 10px; + font-size: 14px; +} + +.line:hover { + background-color: #444; +} + +.button::before { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + -webkit-box-shadow: #959595 0 2px 5px; + -moz-box-shadow: #959595 0 2px 5px; + border-radius: 3px; + box-shadow: #959595 0 2px 5px; + content: ""; + display: block; + left: 0; + padding: 2px 0 0; + position: absolute; + top: 0; +} + +.button:active::before { padding: 1px 0 0; } + +.button.black { + background: #656565; + background: -webkit-gradient(linear, 0 0, 0 bottom, from(#656565), to(#444)); + background: -moz-linear-gradient(#656565, #444); + background: linear-gradient(#656565, #444); + border: solid 1px #535353; + border-bottom: solid 3px #414141; + box-shadow: inset 0 0 0 1px #939393; + color: #fff; + text-shadow: 0 1px 0 #2f2f2f; + padding: 8px 16px; + outline: none; +} + +.button.black:hover { + background: #4c4c4c; + background: -webkit-gradient(linear, 0 0, 0 bottom, from(#4c4c4c), to(#565656)); + background: -moz-linear-gradient(#4c4c4c, #565656); + background: linear-gradient(#4c4c4c, #565656); + border: solid 1px #464646; + border-bottom: solid 3px #414141; + box-shadow: inset 0 0 0 1px #818181; +} + +.button.black:active { + background: #474747; + background: -webkit-gradient(linear, 0 0, 0 bottom, from(#474747), to(#444)); + background: -moz-linear-gradient(#474747, #444); + background: linear-gradient(#474747, #444); + border: solid 1px #2f2f2f; + box-shadow: inset 0 10px 15px 0 #3e3e3e; +} diff --git a/docs/html_extra/examples/webusb-serial/application.js b/docs/html_extra/examples/webusb-serial/application.js new file mode 100644 index 000000000..283121e32 --- /dev/null +++ b/docs/html_extra/examples/webusb-serial/application.js @@ -0,0 +1,90 @@ +(function() { + 'use strict'; + + document.addEventListener('DOMContentLoaded', event => { + let connectButton = document.querySelector("#connect"); + let statusDisplay = document.querySelector('#status'); + let port; + + function addLine(linesId, text) { + var senderLine = document.createElement("div"); + senderLine.className = 'line'; + var textnode = document.createTextNode(text); + senderLine.appendChild(textnode); + document.getElementById(linesId).appendChild(senderLine); + return senderLine; + } + + let currentReceiverLine; + + function appendLine(linesId, text) { + if (currentReceiverLine) { + currentReceiverLine.innerHTML = currentReceiverLine.innerHTML + text; + } else { + currentReceiverLine = addLine(linesId, text); + } + } + + function connect() { + port.connect().then(() => { + statusDisplay.textContent = ''; + connectButton.textContent = 'Disconnect'; + + port.onReceive = data => { + let textDecoder = new TextDecoder(); + console.log(textDecoder.decode(data)); + if (data.getInt8() === 13) { + currentReceiverLine = null; + } else { + appendLine('receiver_lines', textDecoder.decode(data)); + } + }; + port.onReceiveError = error => { + console.error(error); + }; + }, error => { + statusDisplay.textContent = error; + }); + } + + connectButton.addEventListener('click', function() { + if (port) { + port.disconnect(); + connectButton.textContent = 'Connect'; + statusDisplay.textContent = ''; + port = null; + } else { + serial.requestPort().then(selectedPort => { + port = selectedPort; + connect(); + }).catch(error => { + statusDisplay.textContent = error; + }); + } + }); + + serial.getPorts().then(ports => { + if (ports.length === 0) { + statusDisplay.textContent = 'No device found.'; + } else { + statusDisplay.textContent = 'Connecting...'; + port = ports[0]; + connect(); + } + }); + + + let commandLine = document.getElementById("command_line"); + + commandLine.addEventListener("keypress", function(event) { + if (event.keyCode === 13) { + if (commandLine.value.length > 0) { + addLine('sender_lines', commandLine.value); + commandLine.value = ''; + } + } + + port.send(new TextEncoder('utf-8').encode(String.fromCharCode(event.which || event.keyCode))); + }); + }); +})(); diff --git a/docs/html_extra/examples/webusb-serial/index.html b/docs/html_extra/examples/webusb-serial/index.html new file mode 100644 index 000000000..2f1432b0b --- /dev/null +++ b/docs/html_extra/examples/webusb-serial/index.html @@ -0,0 +1,33 @@ +<!DOCTYPE html> +<html> + <head> + <title>TinyUSB</title> + <script src="serial.js"></script> + <script src="application.js"></script> + <link rel="stylesheet" href="application.css"> + </head> + <body> + <div class="main-content"> + <h1>TinyUSB - WebUSB Serial Example</h1> + <div class="connect-container"> + <button id="connect" class="button black">Connect</button> + <span id="status"></span> + </div> + <div class="container"> + <div class="sender"> + <div class="lines-header">Sender</div> + <div class="lines-body"> + <div id="sender_lines" class="lines"></div> + <input id="command_line" class="command-line" placeholder="Start typing ...." /> + </div> + </div> + <div class="receiver"> + <div class="lines-header">Receiver</div> + <div class="lines-body"> + <div id="receiver_lines" class="lines"></div> + </div> + </div> + </div> + </div> + </body> +</html> diff --git a/docs/html_extra/examples/webusb-serial/serial.js b/docs/html_extra/examples/webusb-serial/serial.js new file mode 100644 index 000000000..8e985d897 --- /dev/null +++ b/docs/html_extra/examples/webusb-serial/serial.js @@ -0,0 +1,89 @@ +var serial = {}; + +(function() { + 'use strict'; + + serial.getPorts = function() { + return navigator.usb.getDevices().then(devices => { + return devices.map(device => new serial.Port(device)); + }); + }; + + serial.requestPort = function() { + const filters = [ + { 'vendorId': 0x239A }, // Adafruit boards + { 'vendorId': 0xcafe }, // TinyUSB example + ]; + return navigator.usb.requestDevice({ 'filters': filters }).then( + device => new serial.Port(device) + ); + } + + serial.Port = function(device) { + this.device_ = device; + this.interfaceNumber = 0; + this.endpointIn = 0; + this.endpointOut = 0; + }; + + serial.Port.prototype.connect = function() { + let readLoop = () => { + this.device_.transferIn(this.endpointIn, 64).then(result => { + this.onReceive(result.data); + readLoop(); + }, error => { + this.onReceiveError(error); + }); + }; + + return this.device_.open() + .then(() => { + if (this.device_.configuration === null) { + return this.device_.selectConfiguration(1); + } + }) + .then(() => { + var interfaces = this.device_.configuration.interfaces; + interfaces.forEach(element => { + element.alternates.forEach(elementalt => { + if (elementalt.interfaceClass==0xFF) { + this.interfaceNumber = element.interfaceNumber; + elementalt.endpoints.forEach(elementendpoint => { + if (elementendpoint.direction == "out") { + this.endpointOut = elementendpoint.endpointNumber; + } + if (elementendpoint.direction=="in") { + this.endpointIn =elementendpoint.endpointNumber; + } + }) + } + }) + }) + }) + .then(() => this.device_.claimInterface(this.interfaceNumber)) + .then(() => this.device_.selectAlternateInterface(this.interfaceNumber, 0)) + .then(() => this.device_.controlTransferOut({ + 'requestType': 'class', + 'recipient': 'interface', + 'request': 0x22, + 'value': 0x01, + 'index': this.interfaceNumber})) + .then(() => { + readLoop(); + }); + }; + + serial.Port.prototype.disconnect = function() { + return this.device_.controlTransferOut({ + 'requestType': 'class', + 'recipient': 'interface', + 'request': 0x22, + 'value': 0x00, + 'index': this.interfaceNumber}) + .then(() => this.device_.close()); + }; + + serial.Port.prototype.send = function(data) { + return this.device_.transferOut(this.endpointOut, data); + }; +})(); |
