Skip to content

Commit cbc44d8

Browse files
authored
Merge pull request #20 from adafruit/develop
add webusb-serial demo page
2 parents f24496f + b68728d commit cbc44d8

File tree

4 files changed

+319
-0
lines changed

4 files changed

+319
-0
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
.main-content {
2+
width: 1440px;
3+
margin: auto;
4+
font-size: 14px;
5+
}
6+
7+
.connect-container {
8+
margin: 20px 0;
9+
}
10+
11+
.container {
12+
display: flex;
13+
}
14+
15+
.sender, .receiver {
16+
flex: 1;
17+
}
18+
19+
.sender {
20+
margin-right: 8px;
21+
}
22+
23+
.receiver {
24+
margin-left: 8px;
25+
}
26+
27+
.lines-header {
28+
height: 30px;
29+
width: 100%;
30+
box-sizing: border-box;
31+
background-color: #444;
32+
line-height: 30px;
33+
color: white;
34+
padding-left: 10px;
35+
}
36+
37+
.lines-body {
38+
width: 100%;
39+
background-color: #222;
40+
min-height: 300px;
41+
padding: 10px 0 20px 0;
42+
}
43+
44+
.line, .command-line {
45+
box-sizing: border-box;
46+
width: 100%;
47+
color: #f1f1f1;
48+
background-color: #222;
49+
outline: none;
50+
border: none;
51+
padding: 5px 10px;
52+
font-size: 14px;
53+
}
54+
55+
.line:hover {
56+
background-color: #444;
57+
}
58+
59+
.button::before {
60+
-webkit-border-radius: 3px;
61+
-moz-border-radius: 3px;
62+
-webkit-box-shadow: #959595 0 2px 5px;
63+
-moz-box-shadow: #959595 0 2px 5px;
64+
border-radius: 3px;
65+
box-shadow: #959595 0 2px 5px;
66+
content: "";
67+
display: block;
68+
left: 0;
69+
padding: 2px 0 0;
70+
position: absolute;
71+
top: 0;
72+
}
73+
74+
.button:active::before { padding: 1px 0 0; }
75+
76+
.button.black {
77+
background: #656565;
78+
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#656565), to(#444));
79+
background: -moz-linear-gradient(#656565, #444);
80+
background: linear-gradient(#656565, #444);
81+
border: solid 1px #535353;
82+
border-bottom: solid 3px #414141;
83+
box-shadow: inset 0 0 0 1px #939393;
84+
color: #fff;
85+
text-shadow: 0 1px 0 #2f2f2f;
86+
padding: 8px 16px;
87+
outline: none;
88+
}
89+
90+
.button.black:hover {
91+
background: #4c4c4c;
92+
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#4c4c4c), to(#565656));
93+
background: -moz-linear-gradient(#4c4c4c, #565656);
94+
background: linear-gradient(#4c4c4c, #565656);
95+
border: solid 1px #464646;
96+
border-bottom: solid 3px #414141;
97+
box-shadow: inset 0 0 0 1px #818181;
98+
}
99+
100+
.button.black:active {
101+
background: #474747;
102+
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#474747), to(#444));
103+
background: -moz-linear-gradient(#474747, #444);
104+
background: linear-gradient(#474747, #444);
105+
border: solid 1px #2f2f2f;
106+
box-shadow: inset 0 10px 15px 0 #3e3e3e;
107+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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 port;
8+
9+
function addLine(linesId, text) {
10+
var senderLine = document.createElement("div");
11+
senderLine.className = 'line';
12+
var textnode = document.createTextNode(text);
13+
senderLine.appendChild(textnode);
14+
document.getElementById(linesId).appendChild(senderLine);
15+
return senderLine;
16+
}
17+
18+
let currentReceiverLine;
19+
20+
function appendLine(linesId, text) {
21+
if (currentReceiverLine) {
22+
currentReceiverLine.innerHTML = currentReceiverLine.innerHTML + text;
23+
} else {
24+
currentReceiverLine = addLine(linesId, text);
25+
}
26+
}
27+
28+
function connect() {
29+
port.connect().then(() => {
30+
statusDisplay.textContent = '';
31+
connectButton.textContent = 'Disconnect';
32+
33+
port.onReceive = data => {
34+
let textDecoder = new TextDecoder();
35+
console.log(textDecoder.decode(data));
36+
if (data.getInt8() === 13) {
37+
currentReceiverLine = null;
38+
} else {
39+
appendLine('receiver_lines', textDecoder.decode(data));
40+
}
41+
};
42+
port.onReceiveError = error => {
43+
console.error(error);
44+
};
45+
}, error => {
46+
statusDisplay.textContent = error;
47+
});
48+
}
49+
50+
connectButton.addEventListener('click', function() {
51+
if (port) {
52+
port.disconnect();
53+
connectButton.textContent = 'Connect';
54+
statusDisplay.textContent = '';
55+
port = null;
56+
} else {
57+
serial.requestPort().then(selectedPort => {
58+
port = selectedPort;
59+
connect();
60+
}).catch(error => {
61+
statusDisplay.textContent = error;
62+
});
63+
}
64+
});
65+
66+
serial.getPorts().then(ports => {
67+
if (ports.length === 0) {
68+
statusDisplay.textContent = 'No device found.';
69+
} else {
70+
statusDisplay.textContent = 'Connecting...';
71+
port = ports[0];
72+
connect();
73+
}
74+
});
75+
76+
77+
let commandLine = document.getElementById("command_line");
78+
79+
commandLine.addEventListener("keypress", function(event) {
80+
if (event.keyCode === 13) {
81+
if (commandLine.value.length > 0) {
82+
addLine('sender_lines', commandLine.value);
83+
commandLine.value = '';
84+
}
85+
}
86+
87+
port.send(new TextEncoder('utf-8').encode(String.fromCharCode(event.which || event.keyCode)));
88+
});
89+
});
90+
})();
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>TinyUSB</title>
5+
<script src="serial.js"></script>
6+
<script src="application.js"></script>
7+
<link rel="stylesheet" href="application.css">
8+
</head>
9+
<body>
10+
<div class="main-content">
11+
<h1>TinyUSB's WebUSB Demo</h1>
12+
<div class="connect-container">
13+
<button id="connect" class="button black">Connect</button>
14+
<span id="status"></span>
15+
</div>
16+
<div class="container">
17+
<div class="sender">
18+
<div class="lines-header">Sender</div>
19+
<div class="lines-body">
20+
<div id="sender_lines" class="lines"></div>
21+
<input id="command_line" class="command-line" placeholder="Start typing ...." />
22+
</div>
23+
</div>
24+
<div class="receiver">
25+
<div class="lines-header">Receiver</div>
26+
<div class="lines-body">
27+
<div id="receiver_lines" class="lines"></div>
28+
</div>
29+
</div>
30+
</div>
31+
</div>
32+
</body>
33+
</html>

docs/examples/webusb-serial/serial.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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': 0x239A }, // Adafruit boards
15+
{ 'vendorId': 0xcafe }, // TinyUSB example
16+
];
17+
return navigator.usb.requestDevice({ 'filters': filters }).then(
18+
device => new serial.Port(device)
19+
);
20+
}
21+
22+
serial.Port = function(device) {
23+
this.device_ = device;
24+
this.interfaceNumber = 0;
25+
this.endpointIn = 0;
26+
this.endpointOut = 0;
27+
};
28+
29+
serial.Port.prototype.connect = function() {
30+
let readLoop = () => {
31+
this.device_.transferIn(this.endpointIn, 64).then(result => {
32+
this.onReceive(result.data);
33+
readLoop();
34+
}, error => {
35+
this.onReceiveError(error);
36+
});
37+
};
38+
39+
return this.device_.open()
40+
.then(() => {
41+
if (this.device_.configuration === null) {
42+
return this.device_.selectConfiguration(1);
43+
}
44+
})
45+
.then(() => {
46+
var interfaces = this.device_.configuration.interfaces;
47+
interfaces.forEach(element => {
48+
element.alternates.forEach(elementalt => {
49+
if (elementalt.interfaceClass==0xFF) {
50+
this.interfaceNumber = element.interfaceNumber;
51+
elementalt.endpoints.forEach(elementendpoint => {
52+
if (elementendpoint.direction == "out") {
53+
this.endpointOut = elementendpoint.endpointNumber;
54+
}
55+
if (elementendpoint.direction=="in") {
56+
this.endpointIn =elementendpoint.endpointNumber;
57+
}
58+
})
59+
}
60+
})
61+
})
62+
})
63+
.then(() => this.device_.claimInterface(this.interfaceNumber))
64+
.then(() => this.device_.selectAlternateInterface(this.interfaceNumber, 0))
65+
.then(() => this.device_.controlTransferOut({
66+
'requestType': 'class',
67+
'recipient': 'interface',
68+
'request': 0x22,
69+
'value': 0x01,
70+
'index': this.interfaceNumber}))
71+
.then(() => {
72+
readLoop();
73+
});
74+
};
75+
76+
serial.Port.prototype.disconnect = function() {
77+
return this.device_.controlTransferOut({
78+
'requestType': 'class',
79+
'recipient': 'interface',
80+
'request': 0x22,
81+
'value': 0x00,
82+
'index': this.interfaceNumber})
83+
.then(() => this.device_.close());
84+
};
85+
86+
serial.Port.prototype.send = function(data) {
87+
return this.device_.transferOut(this.endpointOut, data);
88+
};
89+
})();

0 commit comments

Comments
 (0)