blob: 821e67f8b5a869bcc1835721e04333be3674c9cf [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.
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
*/
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() {
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);
}
}