blob: 5150eb7d7f551f457344883dc467546929dfc93a [file] [log] [blame]
// Copyright 2020 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
/* eslint-env browser */
import {BehaviorSubject, Subject} from 'rxjs';
import DeviceTransport from './device_transport';
const DEFAULT_SERIAL_OPTIONS: SerialOptions = {
baudrate: 921600,
databits: 8,
parity: 'none',
stopbits: 1,
};
/**
* WebSerialTransport sends and receives UInt8Arrays to and
* from a serial device connected over USB.
*/
export class WebSerialTransport implements DeviceTransport {
chunks = new Subject<Uint8Array>();
connected = new BehaviorSubject<boolean>(false);
private writer?: WritableStreamDefaultWriter<Uint8Array>;
constructor(
private serial: Serial = navigator.serial,
private filters: SerialPortFilter[] = [],
private serialOptions = DEFAULT_SERIAL_OPTIONS
) {}
/**
* Send a UInt8Array chunk of data to the connected device.
* @param {Uint8Array} chunk The chunk to send
*/
async sendChunk(chunk: Uint8Array): Promise<void> {
if (this.writer !== undefined && this.connected.getValue()) {
await this.writer.ready;
return this.writer.write(chunk);
}
throw new Error('Device not connected');
}
/**
* Attempt to open a connection to a device. This includes
* asking the user to select a serial port and should only
* be called in response to user interaction.
*/
async connect(): Promise<void> {
let port: SerialPort;
try {
port = await this.serial.requestPort({filters: this.filters});
} catch (e) {
// Ignore errors where the user did not select a port.
if (!(e instanceof DOMException)) {
throw e;
}
return;
}
await port.open(this.serialOptions);
this.writer = port.writable.getWriter();
this.getChunks(port);
}
private getChunks(port: SerialPort) {
port.readable.pipeTo(
new WritableStream({
write: chunk => {
this.chunks.next(chunk);
},
close: () => {
port.close();
this.writer?.releaseLock();
this.connected.next(false);
},
abort: () => {
// Reconnect to the port
this.connected.next(false);
this.getChunks(port);
},
})
);
this.connected.next(true);
}
}