summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhathach <[email protected]>2021-08-05 14:06:08 +0700
committerhathach <[email protected]>2021-08-05 14:06:08 +0700
commitb5d218e6845da43f693e5caa31d883de3b997f41 (patch)
tree700d22e28fc17209d264048694aefe9beb59e521
parent2b521e0c101c371d1b0f36d594aa1e20642b9603 (diff)
add html extra for webusb example
-rw-r--r--README.rst2
-rw-r--r--docs/conf.py3
-rw-r--r--docs/html_extra/examples/webusb-serial/application.css107
-rw-r--r--docs/html_extra/examples/webusb-serial/application.js90
-rw-r--r--docs/html_extra/examples/webusb-serial/index.html33
-rw-r--r--docs/html_extra/examples/webusb-serial/serial.js89
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);
+ };
+})();