Search code examples
javascriptserial-portchromiumnavigator

Delayed read performance when using navigator.serial for serial communication


I've been trying out the web serial API in chrome (https://web.dev/serial/) to do some basic communication with an Arduino board. I've noticed quite a substantial delay when reading data from the serial port however. This same issue is present in some demos, but not all.

For instance, using the WebSerial demo linked towards the bottom has a near instantaneous read:

enter image description here

While using the Serial Terminal example results in a read delay. (note the write is triggered at the moment of a character being entered on the keyboard):

enter image description here

WebSerial being open source allows for me to check for differences between my own implementation, however I am seeing performance much like the second example.

As for the relevant code:

this.port = await navigator.serial.requestPort({ filters });

await this.port.open({ baudRate: 115200, bufferSize: 255, dataBits: 8, flowControl: 'none', parity: 'none', stopBits: 1 });
this.open = true;
this.monitor();

private monitor = async () => {
    const dataEndFlag = new Uint8Array([4, 3]);
    while (this.open && this.port?.readable) {
        this.open = true;
        const reader = this.port.readable.getReader();
        try {
            let data: Uint8Array = new Uint8Array([]);
            while (this.open) {
                const { value, done } = await reader.read();
                if (done) {
                    this.open = false;
                    break;
                }
                if (value) {
                    data = Uint8Array.of(...data, ...value);
                }
                if (data.slice(-2).every((val, idx) => val === dataEndFlag[idx])) {
                    const decoded = this.decoder.decode(data);
                    this.messages.push(decoded);
                    data = new Uint8Array([]);
                }
            }
        } catch {
        }
    }
}

public write = async (data: string) => {
    if (this.port?.writable) {
        const writer = this.port.writable.getWriter();
        await writer.write(this.encoder.encode(data));
        writer.releaseLock();
    }
}

The equivalent WebSerial code can be found here, this is pretty much an exact replica. From what I can observe, it seems to hang at await reader.read(); for a brief period of time.

This is occurring both on a Windows 10 device and a macOS Monterey device. The specific hardware device is an Arduino Pro Micro connected to a USB port.

Has anyone experienced this same scenario?

Update: I did some additional testing with more verbose logging. It seems that the time between the write and read is exactly 1 second every time.


Solution

  • the delay may result from SerialEvent() in your arduino script: set Serial.setTimeout(1); This means 1 millisecond instead of default 1000 milliseconds.