August more text challenge second, rushed

The articles

  1. More powerful File interface, File System Access API

preface

In August, we introduced WICG’s file-system-access API (juejin. Cn). This time, we introduce another interesting interface, the Web Serial API. It enables our website to have the ability to read and write serial devices, such as microcontroller, Bluetooth, printer and so on. In short, it helped bridge the gap between the Internet and the physical world.

Introduction from official documents:

The Serial API provides a way for websites to read and write from a serial device through script. Such an API would bridge the web and the physical world, by allowing documents to communicate with devices such as microcontrollers, 3D printers, and other serial devices.

The Web Serial API provides a way for Web sites to read and write from Serial devices via scripts. Such apis would connect the web to the physical world by allowing documents to communicate with devices such as microcontrollers, 3D printers, and other serial devices.

Played with single-chip microcomputer or develop MCU friends all know that a serial port debugging equipment, are generally use a serial port or serial port turn usb line, a head of the board a host, and then the host via a serial port debug software to communicate, and serial debugging software need to use the system underlying ability, general use c/c + + / c # or electron to write, And with the Web Serial API, makes the Web Serial debugging easy!

Those who want to try something new can log on to the website Serial Terminal, which is a Demo developed by Google Chrome LABS based on the Web Serial API. It is a Web version of Serial debugging assistant, but it does not have many functions.

Next, I will use the methods provided by the API to implement similar functions one by one, and combine with the Stm32F407 development board to implement a real-time light intensity visualization demo.

start

Environment set up

In the development process, we need a real Serial Port device to provide data. If there is no device, we can use the Virtual device simulation. The Serial Port uses the Virtual Serial Port Driver software to create the Virtual Serial Port, and then uses the Serial debugging assistant to simulate the device to send data.

The first time we use it, we’ll have to check to see if the browser supports it. If not, just upgrade to the latest version, Chrome and Edge only. The console enters navigator.serial, and as long as it’s not undefined, it’s fine.

Open the serial port

By calling the navigator. Serial. RequestPort () method to choose what we want to open the serial port, because of the serial data can be accepted at any time, in order to avoid blocking the page, the API is designed to be asynchronous, thus it is Promise.

// Select the serial port to open
const port = await navigator.serial.requestPort();
Copy the code

This will bring up a dialog box to select the SerialPort device, which will return a SerialPort object containing the connection status and a series of data exchange methods.

If we have already opened some serial port devices in the current browser, we do not need to select them again next time

// Return an array of previously accessed serial ports
const ports = await navigator.serial.getPorts();
Copy the code

With the serial port object, you can connect by calling port.open() and passing in the appropriate serial port Settings. The parameters are mainly baud rate, stop bit, data bit, parity check, and so on, which are similar to those of serial debugging assistant.

The baud rate is particularly important, set the wrong words received data is a pile of garbled, so to be consistent with the MCU serial port baud rate, but for analog serial port and other simulation equipment, can be any value. Other parameter fields are as follows

  • dataBits: Data bit. The value is 7 or 8.
  • stopBits: The stop bit. The value can be 1 or 2.
  • parity: Whether to perform parity check,"none"Do not use,"even"Parity checking,"odd"Odd parity.
  • bufferSize: buffer size, which must be less than 16MB.
  • flowControl: Flow control,"none"or"hardware".
// Select the serial port
const port = await navigator.serial.requestPort();
// Open the serial port, where my device baud rate is 57600
await port.open({ baudRate: 57600 });
Copy the code

Read the data

After a serial connection, the Readable and Writable objects of the SerialPort object are ReadableStream and WritableStream, respectively. To understand these two objects, Can see (Streams API concepts – Web API interface reference | MDN (mozilla.org).

Readable.getreader ().read() will asynchronously return two properties when listening to a device that has sent data: Value and done represent the data value and the sending state, similar to the value returned by the Uint8Array iterator object in ES6. Value here uses Uint8Array objects to store data. If done is true, the data transmission is complete.

Calling port.readable.getreader () puts the serial port into the locked read/write state. While the readable object’s locked is true, the serial port cannot be turned off.

Asynchronous I/O has a lot of instability, such as buffer overflows, data frame errors, parity failures, device overflows, etc., so we add error handling and use an infinite loop to poll for data reception.

The following is an asynchronous monitoring of serial port data chestnut:

while (port.readable) {
  const reader = port.readable.getReader();
  try {
    while (true) {
      const { value, done } = await reader.read();
      if (done) {
        // After receiving, the serial port is unlocked
        reader.releaseLock();
        break;
      }
      if (value) {
        console.log(value); }}}catch (error) {
    // Error handling}}Copy the code

The console is constantly printing data, and here is my board sending light intensity through the serial port every 200ms.

Serial port Debugging Assistant interface:

All we’re getting is binary stream data, and we have to convert it. All objects in the Steam API have a way of piping binary streams into strings, similar to how we use the FS module’s piped reads and writes in Nodejs.

Create a TextDecoderStream that pipes the read stream from the serial port and the write stream from the textDecoder to perform the Uint8Array to string conversion.

The TextDecoderStream object is responsible for transcoding the binary stream. The default is to convert the binary stream to UTF-8. The encoding type is set by passing in a construct parameter. Effective Encoding types reference Encoding API Encodings – Web APIs | MDN (mozilla.org)

// If the serial port displays garbled Chinese characters, it is likely that the encoding format is incorrect, select "GB2312" as the encoding format.
const textDecoder = new TextDecoderStream('gb2312');
// Connect the pipe before receiving data, so that the data can be converted while receiving
const readableStreamClosed = port.readable.pipeTo(textDecoder.writable);
// The converted data reader
const reader = textDecoder.readable.getReader();

while (true) {
  const { value, done } = await reader.read();
  if (done) {
    reader.releaseLock();
    break;
  }
  console.log(value);
}
Copy the code

Awesome!!! Same as serial debugging assistant.

To send data

Sending data to the device is as simple as calling port.writable.getwriter () to create a transmitter and then build the data we want to send. The data must be Uint8Array objects.

const writer = port.writable.getWriter();
// The following data correspond to the AsCall code of hello
const data = new Uint8Array([104.101.108.108.111]); 
// Launch!!
await writer.write(data);

// The serial port is locked for sending data. Therefore, you need to unlock the serial port after sending data
writer.releaseLock();
Copy the code

Of course, we can’t use ascall code for everything, it’s too troublesome, we want to get what we put in, use TextEncoderStream in front of the sender to help us transcode.

// The default is utf8
const textEncoder = new TextEncoderStream();
const writableStreamClosed = textEncoder.readable.pipeTo(port.writable);
const writer = textEncoder.writable.getWriter();
await writer.write("hello web serial!");
Copy the code

State monitoring

We can listen for device connections and disconnections to proceed to the next step.

// Listen for device connections
navigator.serial.addEventListener("connect".(event) = > {
	console.log('Device connected')});// The listening device is disconnected
navigator.serial.addEventListener("disconnect".(event) = > {
	console.log('Device disconnected')});Copy the code

Close a serial port

When the serial port is unlocked, you can disable it.

await port.close();
Copy the code

Small demo

The above has introduced the general use of the Web Serial API. For more advanced usage, please refer to the official documentation.

Now we can make a small demo: visual display of real-time light intensity based on Web Serial. A STM32F407 development board is used. Since the board is connected to the USB interface and the USART pin of the processor through a USB to serial port chip, the serial port connection can be realized by using THE USB data line instead of the serial port line. The relevant photosensitive AD conversion code has been burned in, just complete the page part.

The board was originally I used to make fingerprint lock, temporary was used to demonstrate, the line is too disorderly, please ignore ha 😁😁.

The page is divided into two parts, the left side shows the chart, the right side shows the serial port data, built with VUE + Echart. The interface code is a hundred or so lines, so do not post the code and use the interface functions described above. Here’s how it works:

Photoresistors are sampled under normal light, flash and cover respectively, and the corresponding results are shown on the web page.

conclusion

In general, Web Serial API is a very good design, make the Web page is no longer bound to run in a sandbox environment, under the authorization by users, two-way communication with realistic physical device, although before the browser can already call camera, microphone and biological characteristics of equipment, but there are still some limitations.

For now, the API standard is still being incubated, but that doesn’t mean it can’t be used in production, as Atwood’s Law puts it:

Any application that can be written in JavaScript, will eventually be written in JavaScript.

Any application that can be written in JavaScript will eventually be written in JavaScript.

The well-known Espruino-javascript for Microcontrollers is a microprocessor’S JavaScript interpreter that makes it possible to control hardware using JavaScript on embedded devices. Its Espruino Web IDE allows code to be edited online and downloaded to the board, where the Web Serial API is used.

In addition, Microsoft and Arduino have their own online programming sites for embedded devices.

For us individual developers, we can also use it to do some interesting things. In addition to being able to present data, we can also use the existing capabilities of the API to develop a web version of the serial port debugging tool that is more functional than Google Demo. Ever to customized according to demand a serial debugging tools generally adopt other language development or electron, now just like ordinary web pages, packaging after deployment, use natural cross-platform characteristics more web platform distribution, or use PWA technology or provide the web browser application installation function as an individual and the team’s small tools.

Hopefully JavaScript will blossom not only on the front end, but also in the embedded Internet of Things.

reference

  • Serial Terminal
  • Espruino Web IDE
  • WICG/serial: Serial ports API for the platform. (github.com)
  • Web Serial API (wicg.github.io)