Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

samples: webusb: Host webusb demo app directly on zephyr doc #62420

Merged
merged 5 commits into from Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/conf.py
Expand Up @@ -284,6 +284,7 @@
(ZEPHYR_BASE / "doc", "[!_]*"),
(ZEPHYR_BASE, "boards/**/*.rst"),
(ZEPHYR_BASE, "boards/**/doc"),
(ZEPHYR_BASE, "samples/**/*.html"),
(ZEPHYR_BASE, "samples/**/*.rst"),
(ZEPHYR_BASE, "samples/**/doc"),
(ZEPHYR_BASE, "snippets/**/*.rst"),
Expand Down
2 changes: 1 addition & 1 deletion samples/subsys/usb/usb.rst
Expand Up @@ -7,4 +7,4 @@ USB device support samples
:maxdepth: 1
:glob:

**/*
**/README
36 changes: 21 additions & 15 deletions samples/subsys/usb/webusb/README.rst
Expand Up @@ -13,7 +13,7 @@ Sample Overview
***************

This simple echo application demonstrates the WebUSB sample application.
This application receives the data and echoed back to the WebUSB
This application receives the data and echoes back to the WebUSB
based web application (web page) running in the browser at host.
This application is intended for testing purposes only. For running
real usecase, implement applications based on the WebUSB API.
Expand All @@ -37,15 +37,15 @@ Build and flash webusb sample with:
:goals: flash
:compact:

Testing with latest Google Chrome on host
*****************************************
Testing with the latest Google Chrome on host
*********************************************

This sample application requires latest Google Chrome, a web page
This sample application requires the latest Google Chrome, a web page
finikorg marked this conversation as resolved.
Show resolved Hide resolved
based on WebUSB API to connect to the USB device and optionally
http server running on localhost to serve the web page.

WebUSB is a powerful new feature added to the Web and it is available
only to secure origins. This means the web page/site that used to
only to secure origins. This means the web page/site that is used to
connect to the device must be served over a secure connection (HTTPS).

Follow these steps to run the demo on your host system:
Expand All @@ -55,20 +55,25 @@ Follow these steps to run the demo on your host system:
#. Implement a web app (web page) using WebUSB API and run
it on localhost.

See the sample at https://github.com/finikorg/webusb-sample
The sample can be found in the webusb sample directory:
:zephyr_file:`samples/subsys/usb/webusb/index.html`.

This sample web page demonstrate how to create and use a WebUSB
This sample web page demonstrates how to create and use a WebUSB
interface, as well as demonstrate the communication between browser
and WebUSB enabled device.

#. To access JS app go to https://finikorg.github.io/webusb-sample/
There are two ways to access this sample page:

#. To host the demo page locally: Clone the repo and start a web server
in the appropriate directory.
* Using Chrome browser go to :doc:`demo`

.. code-block:: console
* Host the demo page locally: Start a web server
in the webusb sample directory.

$ python -m http.server
.. code-block:: console

$ python -m http.server

Using Chrome browser open url http://localhost:8001/

#. Connect the board to your host.

Expand All @@ -78,7 +83,8 @@ Follow these steps to run the demo on your host system:
Note that at the moment WebUSB landing page notification is disabled
in Chrome on Windows. See https://github.com/WICG/webusb#implementation-status

#. Click on Connect button to connect to the device.
#. Click on the :guilabel:`Connect` button to connect to the device.
finikorg marked this conversation as resolved.
Show resolved Hide resolved

#. Send some text to the device by clicking on the Send button. The demo app
will receive the same text from the device and display it in the textarea.
#. Send some text to the device by clicking on the :guilabel:`Send` button.
The demo app will receive the same text from the device and display it in
the text area.
7 changes: 7 additions & 0 deletions samples/subsys/usb/webusb/demo.rst
@@ -0,0 +1,7 @@
:orphan:

kartben marked this conversation as resolved.
Show resolved Hide resolved
WebUSB HTML Demo App
====================

.. raw:: html
:file: index.html
126 changes: 126 additions & 0 deletions samples/subsys/usb/webusb/index.html
@@ -0,0 +1,126 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>WebUSB Serial Sample Application</title>
</head>

<body>
<script>
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': 0x2fe3, 'productId': 0x0100 },
{ 'vendorId': 0x2fe3, 'productId': 0x00a },
{ 'vendorId': 0x8086, 'productId': 0xF8A1 },
];
return navigator.usb.requestDevice({ 'filters': filters }).then(
device => new serial.Port(device)
);
}

serial.Port = function(device) {
this.device_ = device;
};

serial.Port.prototype.connect = function() {
let readLoop = () => {
const {
endpointNumber
} = this.device_.configuration.interfaces[0].alternate.endpoints[0]
this.device_.transferIn(endpointNumber, 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(() => this.device_.claimInterface(0))
.then(() => {
readLoop();
});
};

serial.Port.prototype.disconnect = function() {
return this.device_.close();
};

serial.Port.prototype.send = function(data) {
const {
endpointNumber
} = this.device_.configuration.interfaces[0].alternate.endpoints[1]
return this.device_.transferOut(endpointNumber, data);
};
})();

let port;

function connect() {
port.connect().then(() => {
port.onReceive = data => {
let textDecoder = new TextDecoder();
console.log("Received:", textDecoder.decode(data));
document.getElementById('output').value += textDecoder.decode(data);
}
port.onReceiveError = error => {
console.error(error);
document.querySelector("#connect").style = "visibility: initial";
port.disconnect();
};
});
}

function send(string) {
console.log("sending to serial:" + string.length);
if (string.length === 0)
return;
console.log("sending to serial: [" + string +"]\n");

let view = new TextEncoder('utf-8').encode(string);
console.log(view);
if (port) {
port.send(view);
}
};

window.onload = _ => {
document.querySelector("#connect").onclick = function() {
serial.requestPort().then(selectedPort => {
port = selectedPort;
this.style = "visibility: hidden";
connect();
});
}

document.querySelector("#submit").onclick = () => {
let source = document.querySelector("#input").value;
send(source);
}
}

</script>
<button id="connect" style="visibility: initial">Connect To WebUSB Device</button>
<br><br><label for="input">Sender: </label> <br>
<textarea id="input" rows="25" cols="80">WebUSB!</textarea>
<br><button id="submit">Send</button>
<br><br>
<label for="output">Receiver: </label> <br>
<textarea id="output" rows="25" cols="80"></textarea>
</body>
kartben marked this conversation as resolved.
Show resolved Hide resolved
</html>