mirror of
https://github.com/meshcore-dev/meshcore.js.git
synced 2026-04-20 22:13:49 +00:00
refactor serial connection to base class and web serial class
This commit is contained in:
parent
c18496f788
commit
de4e1d713b
3 changed files with 156 additions and 130 deletions
|
|
@ -190,7 +190,7 @@
|
|||
|
||||
<script type="module">
|
||||
import Constants from "./src/constants.js";
|
||||
import SerialConnection from "./src/connection/serial_connection.js";
|
||||
import WebSerialConnection from "./src/connection/web_serial_connection.js";
|
||||
import BleConnection from "./src/connection/ble_connection.js";
|
||||
import BufferUtils from "./src/buffer_utils.js";
|
||||
Vue.createApp({
|
||||
|
|
@ -209,7 +209,7 @@
|
|||
},
|
||||
methods: {
|
||||
async askForSerialPort() {
|
||||
this.connection = await SerialConnection.open();
|
||||
this.connection = await WebSerialConnection.open();
|
||||
this.connection.on("connected", () => this.onConnected());
|
||||
this.connection.on("disconnected", () => this.onDisconnected());
|
||||
// this.connection.on("tx", (data) => console.log("tx", data));
|
||||
|
|
|
|||
|
|
@ -5,75 +5,16 @@ import Connection from "./connection.js";
|
|||
|
||||
class SerialConnection extends Connection {
|
||||
|
||||
constructor(serialPort) {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.serialPort = serialPort;
|
||||
this.reader = serialPort.readable.getReader();
|
||||
this.writable = serialPort.writable;
|
||||
this.readBuffer = [];
|
||||
this.readLoop();
|
||||
|
||||
// listen for disconnect
|
||||
this.serialPort.addEventListener("disconnect", () => {
|
||||
this.onDisconnected();
|
||||
});
|
||||
|
||||
// fire connected callback after constructor has returned
|
||||
setTimeout(() => {
|
||||
this.onConnected();
|
||||
}, 0);
|
||||
|
||||
}
|
||||
|
||||
static async open() {
|
||||
|
||||
// ensure browser supports web serial
|
||||
if(!navigator.serial){
|
||||
alert("Web Serial is not supported in this browser");
|
||||
return null;
|
||||
if(this.constructor === SerialConnection){
|
||||
throw new Error("SerialConnection is an abstract class and can't be instantiated.");
|
||||
}
|
||||
|
||||
// ask user to select device
|
||||
const serialPort = await navigator.serial.requestPort({
|
||||
filters: [],
|
||||
});
|
||||
|
||||
// open port
|
||||
await serialPort.open({
|
||||
baudRate: 115200,
|
||||
});
|
||||
|
||||
return new SerialConnection(serialPort);
|
||||
|
||||
}
|
||||
|
||||
async close() {
|
||||
|
||||
// release reader lock
|
||||
try {
|
||||
this.reader.releaseLock();
|
||||
} catch(e) {
|
||||
// console.log("failed to release lock on serial port readable, ignoring...", e);
|
||||
}
|
||||
|
||||
// close serial port
|
||||
try {
|
||||
await this.serialPort.close();
|
||||
} catch(e) {
|
||||
// console.log("failed to close serial port, ignoring...", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async write(bytes) {
|
||||
const writer = this.writable.getWriter();
|
||||
try {
|
||||
await writer.write(new Uint8Array(bytes));
|
||||
} finally {
|
||||
writer.releaseLock();
|
||||
}
|
||||
throw new Error("Not Implemented: write must be implemented by SerialConnection sub class.");
|
||||
}
|
||||
|
||||
async writeFrame(frameType, frameData) {
|
||||
|
|
@ -99,79 +40,58 @@ class SerialConnection extends Connection {
|
|||
await this.writeFrame(0x3c, data);
|
||||
}
|
||||
|
||||
async readLoop() {
|
||||
try {
|
||||
while(true){
|
||||
async onDataReceived(value) {
|
||||
|
||||
// read bytes until reader indicates it's done
|
||||
const { value, done } = await this.reader.read();
|
||||
if(done){
|
||||
// append received bytes to read buffer
|
||||
this.readBuffer = [
|
||||
...this.readBuffer,
|
||||
...value,
|
||||
];
|
||||
|
||||
// process read buffer while there is enough bytes for a frame header
|
||||
// 3 bytes frame header = (1 byte frame type) + (2 bytes frame length as unsigned 16-bit little endian)
|
||||
const frameHeaderLength = 3;
|
||||
while(this.readBuffer.length >= frameHeaderLength){
|
||||
try {
|
||||
|
||||
// extract frame header
|
||||
const frameHeader = new BufferReader(this.readBuffer.slice(0, frameHeaderLength));
|
||||
|
||||
// ensure frame type supported
|
||||
const frameType = frameHeader.readByte();
|
||||
if(frameType !== Constants.SerialFrameTypes.Incoming && frameType !== Constants.SerialFrameTypes.Outgoing){
|
||||
// unexpected byte, lets skip it and try again
|
||||
this.readBuffer = this.readBuffer.slice(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// ensure frame length valid
|
||||
const frameLength = frameHeader.readUInt16LE();
|
||||
if(!frameLength){
|
||||
// unexpected byte, lets skip it and try again
|
||||
this.readBuffer = this.readBuffer.slice(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if we have received enough bytes for this frame, otherwise wait until more bytes received
|
||||
const requiredLength = frameHeaderLength + frameLength;
|
||||
if(this.readBuffer.length < requiredLength){
|
||||
break;
|
||||
}
|
||||
|
||||
// append received bytes to read buffer
|
||||
this.readBuffer = [
|
||||
...this.readBuffer,
|
||||
...value,
|
||||
];
|
||||
// get frame data, and remove it and its frame header from the read buffer
|
||||
const frameData = this.readBuffer.slice(frameHeaderLength, requiredLength);
|
||||
this.readBuffer = this.readBuffer.slice(requiredLength);
|
||||
|
||||
// process read buffer while there is enough bytes for a frame header
|
||||
// 3 bytes frame header = (1 byte frame type) + (2 bytes frame length as unsigned 16-bit little endian)
|
||||
const frameHeaderLength = 3;
|
||||
while(this.readBuffer.length >= frameHeaderLength){
|
||||
try {
|
||||
|
||||
// extract frame header
|
||||
const frameHeader = new BufferReader(this.readBuffer.slice(0, frameHeaderLength));
|
||||
|
||||
// ensure frame type supported
|
||||
const frameType = frameHeader.readByte();
|
||||
if(frameType !== Constants.SerialFrameTypes.Incoming && frameType !== Constants.SerialFrameTypes.Outgoing){
|
||||
// unexpected byte, lets skip it and try again
|
||||
this.readBuffer = this.readBuffer.slice(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// ensure frame length valid
|
||||
const frameLength = frameHeader.readUInt16LE();
|
||||
if(!frameLength){
|
||||
// unexpected byte, lets skip it and try again
|
||||
this.readBuffer = this.readBuffer.slice(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if we have received enough bytes for this frame, otherwise wait until more bytes received
|
||||
const requiredLength = frameHeaderLength + frameLength;
|
||||
if(this.readBuffer.length < requiredLength){
|
||||
break;
|
||||
}
|
||||
|
||||
// get frame data, and remove it and its frame header from the read buffer
|
||||
const frameData = this.readBuffer.slice(frameHeaderLength, requiredLength);
|
||||
this.readBuffer = this.readBuffer.slice(requiredLength);
|
||||
|
||||
// handle received frame
|
||||
this.onFrameReceived(frameData);
|
||||
|
||||
} catch(e) {
|
||||
console.error("Failed to process frame", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// handle received frame
|
||||
this.onFrameReceived(frameData);
|
||||
|
||||
} catch(e) {
|
||||
console.error("Failed to process frame", e);
|
||||
break;
|
||||
}
|
||||
} catch(error) {
|
||||
|
||||
// ignore error if reader was released
|
||||
if(error instanceof TypeError){
|
||||
return;
|
||||
}
|
||||
|
||||
console.error('Error reading from serial port: ', error);
|
||||
|
||||
} finally {
|
||||
this.reader.releaseLock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
106
src/connection/web_serial_connection.js
Normal file
106
src/connection/web_serial_connection.js
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
import SerialConnection from "./serial_connection.js";
|
||||
|
||||
class WebSerialConnection extends SerialConnection {
|
||||
|
||||
constructor(serialPort) {
|
||||
|
||||
super();
|
||||
|
||||
this.serialPort = serialPort;
|
||||
this.reader = serialPort.readable.getReader();
|
||||
this.writable = serialPort.writable;
|
||||
this.readLoop();
|
||||
|
||||
// listen for disconnect
|
||||
this.serialPort.addEventListener("disconnect", () => {
|
||||
this.onDisconnected();
|
||||
});
|
||||
|
||||
// fire connected callback after constructor has returned
|
||||
setTimeout(() => {
|
||||
this.onConnected();
|
||||
}, 0);
|
||||
|
||||
}
|
||||
|
||||
static async open() {
|
||||
|
||||
// ensure browser supports web serial
|
||||
if(!navigator.serial){
|
||||
alert("Web Serial is not supported in this browser");
|
||||
return null;
|
||||
}
|
||||
|
||||
// ask user to select device
|
||||
const serialPort = await navigator.serial.requestPort({
|
||||
filters: [],
|
||||
});
|
||||
|
||||
// open port
|
||||
await serialPort.open({
|
||||
baudRate: 115200,
|
||||
});
|
||||
|
||||
return new WebSerialConnection(serialPort);
|
||||
|
||||
}
|
||||
|
||||
async close() {
|
||||
|
||||
// release reader lock
|
||||
try {
|
||||
this.reader.releaseLock();
|
||||
} catch(e) {
|
||||
// console.log("failed to release lock on serial port readable, ignoring...", e);
|
||||
}
|
||||
|
||||
// close serial port
|
||||
try {
|
||||
await this.serialPort.close();
|
||||
} catch(e) {
|
||||
// console.log("failed to close serial port, ignoring...", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// override
|
||||
async write(bytes) {
|
||||
const writer = this.writable.getWriter();
|
||||
try {
|
||||
await writer.write(new Uint8Array(bytes));
|
||||
} finally {
|
||||
writer.releaseLock();
|
||||
}
|
||||
}
|
||||
|
||||
async readLoop() {
|
||||
try {
|
||||
while(true){
|
||||
|
||||
// read bytes until reader indicates it's done
|
||||
const { value, done } = await this.reader.read();
|
||||
if(done){
|
||||
break;
|
||||
}
|
||||
|
||||
// pass to super class handler
|
||||
await this.onDataReceived(value);
|
||||
|
||||
}
|
||||
} catch(error) {
|
||||
|
||||
// ignore error if reader was released
|
||||
if(error instanceof TypeError){
|
||||
return;
|
||||
}
|
||||
|
||||
console.error('Error reading from serial port: ', error);
|
||||
|
||||
} finally {
|
||||
this.reader.releaseLock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebSerialConnection;
|
||||
Loading…
Add table
Add a link
Reference in a new issue