2025-02-23 10:19:53 +01:00
|
|
|
function delay(msecs) {
|
|
|
|
|
return new Promise((resolve) => setTimeout(resolve, msecs));
|
|
|
|
|
}
|
2026-01-10 23:15:50 +01:00
|
|
|
|
2025-02-23 10:19:53 +01:00
|
|
|
class LineBreakTransformer {
|
|
|
|
|
chunks = '';
|
|
|
|
|
port = null;
|
|
|
|
|
|
|
|
|
|
transform(chunk, controller) {
|
|
|
|
|
// Append new chunks to existing chunks.
|
|
|
|
|
this.chunks += chunk;
|
|
|
|
|
// For each line breaks in chunks, send the parsed lines out.
|
|
|
|
|
const lines = this.chunks.split('\r\n');
|
|
|
|
|
this.chunks = lines.pop();
|
|
|
|
|
lines.forEach((line) => controller.enqueue(line + '\r\n'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flush(controller) {
|
|
|
|
|
// When the stream is closed, flush any remaining chunks out.
|
|
|
|
|
controller.enqueue(this.chunks);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class SerialConsole {
|
|
|
|
|
connected = false;
|
|
|
|
|
constructor(port) {
|
|
|
|
|
this.port = port;
|
|
|
|
|
this.controller = new AbortController();
|
|
|
|
|
this.signal = this.controller.signal;
|
|
|
|
|
this.onOutput = (text) => {
|
|
|
|
|
console.log(text);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async connect() {
|
|
|
|
|
try {
|
|
|
|
|
await this.port.open({ baudRate: 115200 });
|
|
|
|
|
this.connected = true;
|
|
|
|
|
await this.port.readable
|
|
|
|
|
.pipeThrough(new TextDecoderStream(), { signal: this.signal })
|
|
|
|
|
.pipeThrough(new TransformStream(new LineBreakTransformer()))
|
|
|
|
|
.pipeTo(
|
|
|
|
|
new WritableStream({
|
|
|
|
|
write: (chunk) => {
|
|
|
|
|
this.addLine(chunk.replace('\r', ''));
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Check AFTER the pipeTo has completed (or been aborted)
|
|
|
|
|
if (!this.signal.aborted) {
|
|
|
|
|
this.addLine('\n\n*** Terminal disconnected');
|
|
|
|
|
this.connected = false;
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
this.addLine(`\n\n*** Terminal disconnected: ${e}`);
|
|
|
|
|
this.connected = false;
|
|
|
|
|
} finally {
|
|
|
|
|
await delay(100);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addLine(text) {
|
|
|
|
|
this.onOutput(text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async sendCommand(command) {
|
|
|
|
|
const encoder = new TextEncoder();
|
|
|
|
|
const writer = this.port.writable.getWriter(); // Get writer from 'this.port'
|
|
|
|
|
await writer.write(encoder.encode(command + '\r\n'));
|
|
|
|
|
try {
|
|
|
|
|
writer.releaseLock();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error('Ignoring release lock error', err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async disconnect() {
|
|
|
|
|
this.controller.abort();
|
|
|
|
|
await delay(50);
|
|
|
|
|
await this.port.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async reset() {
|
|
|
|
|
console.debug('Triggering reset');
|
|
|
|
|
await this.port.setSignals({
|
|
|
|
|
dataTerminalReady: false,
|
|
|
|
|
requestToSend: true,
|
|
|
|
|
});
|
|
|
|
|
await delay(250);
|
|
|
|
|
await this.port.setSignals({
|
|
|
|
|
dataTerminalReady: false,
|
|
|
|
|
requestToSend: false,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await delay(1250);
|
|
|
|
|
}
|
|
|
|
|
}
|