deps(core): 更新esptool
This commit is contained in:
@@ -9,117 +9,92 @@ const { Web } = Mixly;
|
||||
class Transport {
|
||||
slipReaderEnabled = false;
|
||||
baudrate = 0;
|
||||
traceLog = "";
|
||||
|
||||
traceLog = '';
|
||||
lastTraceTime = Date.now();
|
||||
|
||||
buffer = new Uint8Array(0);
|
||||
serial = null;
|
||||
tracing = false;
|
||||
|
||||
_DTR_state = false;
|
||||
|
||||
SLIP_END = 0xc0;
|
||||
SLIP_ESC = 0xdb;
|
||||
SLIP_ESC_END = 0xdc;
|
||||
SLIP_ESC_ESC = 0xdd;
|
||||
|
||||
constructor(serial, tracing = false, enableSlipReader = true) {
|
||||
this.serial = serial;
|
||||
this.tracing = tracing;
|
||||
this.slipReaderEnabled = enableSlipReader;
|
||||
|
||||
this.serial.bind('onBuffer', (data) => {
|
||||
if (!(data instanceof Uint8Array)) data = new Uint8Array(data);
|
||||
if (!(data instanceof Uint8Array)) {
|
||||
data = new Uint8Array(data);
|
||||
}
|
||||
this.buffer = this.appendArray(this.buffer, data);
|
||||
if (this.tracing)
|
||||
this.trace(`Received ${data.length} bytes: ${this.hexConvert(data)}`);
|
||||
|
||||
if (this.tracing) {
|
||||
this.trace(`Read ${data.length} bytes: ${this.hexConvert(data)}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getInfo() {
|
||||
const VID = this.serial.getVID();
|
||||
const PID = this.serial.getPID();
|
||||
return `WebDevice VendorID 0x${VID.toString(16)} ProductID 0x${PID.toString(16)}`;
|
||||
const VID = this.serial.getVID?.();
|
||||
const PID = this.serial.getPID?.();
|
||||
return (VID && PID)
|
||||
? `WebDevice VendorID 0x${VID.toString(16)} ProductID 0x${PID.toString(16)}`
|
||||
: '';
|
||||
}
|
||||
|
||||
getPid() {
|
||||
return this.serial.getPID();
|
||||
return this.serial.getPID?.();
|
||||
}
|
||||
|
||||
trace(message) {
|
||||
const delta = Date.now() - this.lastTraceTime;
|
||||
const prefix = `TRACE +${delta}ms`;
|
||||
const traceMessage = `${prefix} ${message}`;
|
||||
const traceMessage = `TRACE +${delta}ms ${message}`;
|
||||
this.lastTraceTime = Date.now();
|
||||
console.log(traceMessage);
|
||||
this.traceLog += traceMessage + "\n";
|
||||
|
||||
// console.log(traceMessage);
|
||||
this.traceLog += traceMessage + '\n';
|
||||
}
|
||||
|
||||
async returnTrace() {
|
||||
try {
|
||||
await navigator.clipboard.writeText(this.traceLog);
|
||||
console.log("Trace log copied to clipboard!");
|
||||
} catch (err) {
|
||||
console.error("Failed to copy trace log:", err);
|
||||
await navigator.clipboard.writeText(this.traceLog);
|
||||
}
|
||||
|
||||
hexify(arr) {
|
||||
return Array.from(arr)
|
||||
.map(b => b.toString(16).padStart(2, '0'))
|
||||
.join(' ')
|
||||
.padEnd(16, ' ');
|
||||
}
|
||||
|
||||
hexConvert(arr, autoSplit = true) {
|
||||
if (!autoSplit || arr.length <= 16) {
|
||||
return this.hexify(arr);
|
||||
}
|
||||
}
|
||||
|
||||
hexify(s) {
|
||||
return Array.from(s)
|
||||
.map((byte) => byte.toString(16).padStart(2, "0"))
|
||||
.join(" ")
|
||||
.padEnd(16, " ");
|
||||
}
|
||||
|
||||
hexConvert(uint8Array, autoSplit = true) {
|
||||
if (autoSplit && uint8Array.length > 16) {
|
||||
let result = "";
|
||||
let s = uint8Array;
|
||||
while (s.length > 0) {
|
||||
const line = s.slice(0, 16);
|
||||
const asciiLine = String.fromCharCode(...line)
|
||||
.split("")
|
||||
.map((c) =>
|
||||
c === " " || (c >= " " && c <= "~" && c !== " ") ? c : "."
|
||||
)
|
||||
.join("");
|
||||
s = s.slice(16);
|
||||
result += `\n ${this.hexify(line.slice(0, 8))} ${this.hexify(
|
||||
line.slice(8)
|
||||
)} | ${asciiLine}`;
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return this.hexify(uint8Array);
|
||||
let out = '';
|
||||
let s = arr;
|
||||
while (s.length) {
|
||||
const line = s.slice(0, 16);
|
||||
const ascii = String.fromCharCode(...line)
|
||||
.replace(/[^\x20-\x7E]/g, '.');
|
||||
s = s.slice(16);
|
||||
out += `\n ${this.hexify(line.slice(0,8))} ${this.hexify(line.slice(8))} | ${ascii}`;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
appendArray(arr1, arr2) {
|
||||
const combined = new Uint8Array(arr1.length + arr2.length);
|
||||
combined.set(arr1);
|
||||
combined.set(arr2, arr1.length);
|
||||
return combined;
|
||||
}
|
||||
|
||||
async sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async connect(baud = 115200) {
|
||||
await this.serial.open(baud);
|
||||
this.baudrate = baud;
|
||||
if (this.tracing) this.trace(`Serial opened at ${baud} baud`);
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
await this.serial.close();
|
||||
if (this.tracing) this.trace("Serial connection closed");
|
||||
}
|
||||
|
||||
async setRTS(state) {
|
||||
await this.serial.setRTS(state);
|
||||
await this.serial.setDTR(this.serial.getDTR());
|
||||
if (this.tracing) {
|
||||
this.trace(`Set RTS = ${state}`);
|
||||
this.trace(`Set DTR = ${this.serial.getDTR()}`);
|
||||
}
|
||||
}
|
||||
|
||||
async setDTR(state) {
|
||||
await this.serial.setDTR(state);
|
||||
if (this.tracing) this.trace(`Set DTR = ${state}`);
|
||||
appendArray(a, b) {
|
||||
const out = new Uint8Array(a.length + b.length);
|
||||
out.set(a);
|
||||
out.set(b, a.length);
|
||||
return out;
|
||||
}
|
||||
|
||||
inWaiting() {
|
||||
@@ -131,95 +106,126 @@ class Transport {
|
||||
}
|
||||
|
||||
slipWriter(data) {
|
||||
const outData = [];
|
||||
outData.push(0xc0);
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i] === 0xdb) outData.push(0xdb, 0xdd);
|
||||
else if (data[i] === 0xc0) outData.push(0xdb, 0xdc);
|
||||
else outData.push(data[i]);
|
||||
const out = [this.SLIP_END];
|
||||
for (const b of data) {
|
||||
if (b === this.SLIP_END) out.push(this.SLIP_ESC, this.SLIP_ESC_END);
|
||||
else if (b === this.SLIP_ESC) out.push(this.SLIP_ESC, this.SLIP_ESC_ESC);
|
||||
else out.push(b);
|
||||
}
|
||||
outData.push(0xc0);
|
||||
return new Uint8Array(outData);
|
||||
out.push(this.SLIP_END);
|
||||
return new Uint8Array(out);
|
||||
}
|
||||
|
||||
async write(data) {
|
||||
const outData = this.slipWriter(data);
|
||||
const out = this.slipReaderEnabled ? this.slipWriter(data) : data;
|
||||
|
||||
if (this.tracing) {
|
||||
this.trace(`Write ${outData.length} bytes: ${this.hexConvert(outData)}`);
|
||||
this.trace(`Write ${out.length} bytes: ${this.hexConvert(out)}`);
|
||||
}
|
||||
await this.serial.sendBuffer(outData);
|
||||
await this.serial.sendBuffer(out);
|
||||
}
|
||||
|
||||
async newRead(numBytes, timeout) {
|
||||
const start = Date.now();
|
||||
while (this.buffer.length < numBytes && Date.now() - start < timeout) {
|
||||
if (!this.serial.isOpened()) {
|
||||
return null;
|
||||
}
|
||||
await this.sleep(10);
|
||||
|
||||
while (this.buffer.length < numBytes) {
|
||||
if (!this.serial.isOpened()) return null;
|
||||
if (Date.now() - start > timeout) break;
|
||||
await this.sleep(5);
|
||||
}
|
||||
|
||||
const out = this.buffer.slice(0, numBytes);
|
||||
this.buffer = this.buffer.slice(numBytes);
|
||||
return out;
|
||||
}
|
||||
|
||||
async *read(timeout = 1000) {
|
||||
let partialPacket = null;
|
||||
let isEscaping = false;
|
||||
const SLIP_END = 0xc0;
|
||||
const SLIP_ESC = 0xdb;
|
||||
const SLIP_ESC_END = 0xdc;
|
||||
const SLIP_ESC_ESC = 0xdd;
|
||||
let partial = null;
|
||||
let escaping = false;
|
||||
let successfulSlip = false;
|
||||
|
||||
while (true) {
|
||||
const data = await this.newRead(1, timeout);
|
||||
if (!data || data.length === 0) break;
|
||||
const chunk = await this.newRead(1, timeout);
|
||||
if (!chunk || chunk.length === 0) {
|
||||
const msg = partial
|
||||
? 'Packet content transfer stopped'
|
||||
: successfulSlip
|
||||
? 'Serial stream stopped'
|
||||
: 'No serial data received';
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
const byte = data[0];
|
||||
if (partialPacket === null) {
|
||||
if (byte === SLIP_END) partialPacket = new Uint8Array(0);
|
||||
} else if (isEscaping) {
|
||||
isEscaping = false;
|
||||
if (byte === SLIP_ESC_END)
|
||||
partialPacket = this.appendArray(partialPacket, new Uint8Array([SLIP_END]));
|
||||
else if (byte === SLIP_ESC_ESC)
|
||||
partialPacket = this.appendArray(partialPacket, new Uint8Array([SLIP_ESC]));
|
||||
else throw new Error(`Invalid SLIP escape: 0x${byte.toString(16)}`);
|
||||
} else if (byte === SLIP_ESC) {
|
||||
isEscaping = true;
|
||||
} else if (byte === SLIP_END) {
|
||||
if (partialPacket.length > 0) {
|
||||
if (this.tracing)
|
||||
this.trace(`Yield packet: ${this.hexConvert(partialPacket)}`);
|
||||
yield partialPacket;
|
||||
partialPacket = null;
|
||||
const byte = chunk[0];
|
||||
|
||||
if (partial === null) {
|
||||
if (byte === this.SLIP_END) {
|
||||
partial = new Uint8Array(0);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (escaping) {
|
||||
escaping = false;
|
||||
if (byte === this.SLIP_ESC_END)
|
||||
partial = this.appendArray(partial, new Uint8Array([this.SLIP_END]));
|
||||
else if (byte === this.SLIP_ESC_ESC)
|
||||
partial = this.appendArray(partial, new Uint8Array([this.SLIP_ESC]));
|
||||
else
|
||||
throw new Error(`Invalid SLIP escape 0xdb 0x${byte.toString(16)}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (byte === this.SLIP_ESC) {
|
||||
escaping = true;
|
||||
} else if (byte === this.SLIP_END) {
|
||||
if (this.tracing) {
|
||||
this.trace(`Received packet: ${this.hexConvert(partial)}`);
|
||||
}
|
||||
successfulSlip = true;
|
||||
yield partial;
|
||||
partial = null;
|
||||
} else {
|
||||
partialPacket = this.appendArray(partialPacket, new Uint8Array([byte]));
|
||||
partial = this.appendArray(partial, new Uint8Array([byte]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
detectPanicHandler(input) {
|
||||
const guruMeditationRegex =
|
||||
/G?uru Meditation Error: (?:Core \d panic'ed \(([a-zA-Z ]*)\))?/;
|
||||
const fatalExceptionRegex =
|
||||
/F?atal exception \(\d+\): (?:([a-zA-Z ]*)?.*epc)?/;
|
||||
|
||||
const inputString = new TextDecoder("utf-8").decode(input);
|
||||
const match =
|
||||
inputString.match(guruMeditationRegex) ||
|
||||
inputString.match(fatalExceptionRegex);
|
||||
|
||||
if (match) {
|
||||
const cause = match[1] || match[2];
|
||||
const msg = `Guru Meditation Error detected${cause ? ` (${cause})` : ""}`;
|
||||
throw new Error(msg);
|
||||
const text = new TextDecoder().decode(input);
|
||||
const guru = /G?uru Meditation Error/;
|
||||
const fatal = /F?atal exception \(\d+\)/;
|
||||
if (guru.test(text) || fatal.test(text)) {
|
||||
throw new Error('Guru Meditation Error detected');
|
||||
}
|
||||
}
|
||||
|
||||
async setRTS(state) {
|
||||
await this.serial.setRTS(state);
|
||||
await this.setDTR(this._DTR_state);
|
||||
}
|
||||
|
||||
async setDTR(state) {
|
||||
this._DTR_state = state;
|
||||
await this.serial.setDTR(state);
|
||||
}
|
||||
|
||||
async connect(baud = 115200) {
|
||||
await this.serial.open(baud);
|
||||
this.baudrate = baud;
|
||||
if (this.tracing) this.trace(`Serial opened @${baud}`);
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
await this.serial.close();
|
||||
this.buffer = new Uint8Array(0);
|
||||
if (this.tracing) this.trace('Serial closed');
|
||||
}
|
||||
|
||||
sleep(ms) {
|
||||
return new Promise(r => setTimeout(r, ms));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Web.SerialTransport = Transport;
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user