@tomneutens/serial_monitor
Version:
A web based serial monitor for communicating with serial devices (like Arduino). The library is based on native web components and uses the WebSerial API to communicate with the external device.
142 lines (118 loc) • 4.85 kB
text/typescript
/**
* @author Tom Neutens <tomneutens@gmail.com>
*/
import OpenSerialPortError from "../errors/OpenSerialPortError"
class WebSerialConnection {
private baudRate: number
private openPort: SerialPort|null
private serialConnected: boolean
private serialDataEventHandlers: Array<Function>
private serialDisconnectEventHandlers: Array<Function>
private serialConnectEventHandlers: Array<Function>
private sendQueue: Array<number>
constructor(){
this.serialConnected = false
this.openPort = null
this.serialDataEventHandlers = new Array<Function>()
this.serialDisconnectEventHandlers = new Array<Function>()
this.serialConnectEventHandlers = new Array<Function>()
this.sendQueue = new Array<number>()
}
addSerialDataEventHandler(handler: Function){
this.serialDataEventHandlers.push(handler)
}
addSerialDisconnectEventHandler(handler: Function){
this.serialDisconnectEventHandlers.push(handler)
}
addSerialConnectEventHandler(handler: Function){
this.serialConnectEventHandlers.push(handler)
}
sendByte(byte: number){
this.sendQueue.push(byte)
}
private notifyDataHandlers(data: number){
this.serialDataEventHandlers.forEach(handler => handler(data))
}
private notifyConnectHandlers(){
this.serialConnectEventHandlers.forEach(handler => handler())
}
private notifyDisconnectHandlers() {
this.serialDisconnectEventHandlers.forEach(handler => handler())
}
private hasWebSerialSupport(){
if ("serial" in navigator){
return true
} else {
window.alert("Webserial not supported by your browser. Consider using chrome or edge.");
return false
}
}
disconnect() {
this.serialConnected = false;
}
async connect(baudRate: number, filters: SerialPortFilter[] = []) {
if (!this.hasWebSerialSupport()){
return
}
this.baudRate = baudRate;
let stopped = false
try {
let port = await navigator.serial.requestPort({ filters: filters })
// asynchronously start listening to port
port.open({baudRate: this.baudRate}).then(async () => {
this.notifyConnectHandlers()
this.serialConnected = true;
while (port.readable && port.writable && !stopped) {
const reader:ReadableStreamDefaultReader<Uint8Array> = port.readable.getReader();
const writer:WritableStreamDefaultWriter<Uint8Array> = port.writable.getWriter();
this.openPort = port;
try {
while (true && !stopped) {
const { value, done } = await reader.read();
if (!this.serialConnected || done) {
reader.cancel();
writer.releaseLock();
// |reader| has been canceled.
stopped = true;
}
if (value){
value.forEach((element) => { this.notifyDataHandlers(element); });
}
if (this.sendQueue.length > 0){
let nextOnQueue = this.sendQueue.shift() as number
let data = new Uint8Array([nextOnQueue]);
await writer.write(data);
}
}
} catch (error) {
// Handle |error|…
this.openPort = null;
this.serialConnected = false;
} finally {
reader.releaseLock();
this.notifyDisconnectHandlers()
}
}
port.close();
}).catch((error) => {
console.error(error);
})
} catch (error) {
console.error(error)
this.serialConnected = false;
this.notifyDisconnectHandlers()
}
}
setupWebSerial(){
if (navigator.serial){
navigator.serial.addEventListener('connect', (e:any) => {
});
navigator.serial.addEventListener('disconnect', (e:any) => {
this.notifyDisconnectHandlers();
});
navigator.serial.getPorts().then((ports:SerialPort[]) => {
});
}
}
}
export default WebSerialConnection