deps(core): 更新esptool

This commit is contained in:
王立帮
2026-01-16 21:03:03 +08:00
parent f49a2c1e64
commit 2683846d8b
2 changed files with 145 additions and 139 deletions

View File

@@ -9,117 +9,92 @@ const { Web } = Mixly;
class Transport { class Transport {
slipReaderEnabled = false; slipReaderEnabled = false;
baudrate = 0; baudrate = 0;
traceLog = "";
traceLog = '';
lastTraceTime = Date.now(); lastTraceTime = Date.now();
buffer = new Uint8Array(0); buffer = new Uint8Array(0);
serial = null; serial = null;
tracing = false; 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) { constructor(serial, tracing = false, enableSlipReader = true) {
this.serial = serial; this.serial = serial;
this.tracing = tracing; this.tracing = tracing;
this.slipReaderEnabled = enableSlipReader; this.slipReaderEnabled = enableSlipReader;
this.serial.bind('onBuffer', (data) => { 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); 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() { getInfo() {
const VID = this.serial.getVID(); const VID = this.serial.getVID?.();
const PID = this.serial.getPID(); const PID = this.serial.getPID?.();
return `WebDevice VendorID 0x${VID.toString(16)} ProductID 0x${PID.toString(16)}`; return (VID && PID)
? `WebDevice VendorID 0x${VID.toString(16)} ProductID 0x${PID.toString(16)}`
: '';
} }
getPid() { getPid() {
return this.serial.getPID(); return this.serial.getPID?.();
} }
trace(message) { trace(message) {
const delta = Date.now() - this.lastTraceTime; const delta = Date.now() - this.lastTraceTime;
const prefix = `TRACE +${delta}ms`; const traceMessage = `TRACE +${delta}ms ${message}`;
const traceMessage = `${prefix} ${message}`;
this.lastTraceTime = Date.now(); this.lastTraceTime = Date.now();
console.log(traceMessage);
this.traceLog += traceMessage + "\n"; // console.log(traceMessage);
this.traceLog += traceMessage + '\n';
} }
async returnTrace() { async returnTrace() {
try { await navigator.clipboard.writeText(this.traceLog);
await navigator.clipboard.writeText(this.traceLog); }
console.log("Trace log copied to clipboard!");
} catch (err) { hexify(arr) {
console.error("Failed to copy trace log:", err); 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) { let out = '';
return Array.from(s) let s = arr;
.map((byte) => byte.toString(16).padStart(2, "0")) while (s.length) {
.join(" ") const line = s.slice(0, 16);
.padEnd(16, " "); const ascii = String.fromCharCode(...line)
} .replace(/[^\x20-\x7E]/g, '.');
s = s.slice(16);
hexConvert(uint8Array, autoSplit = true) { out += `\n ${this.hexify(line.slice(0,8))} ${this.hexify(line.slice(8))} | ${ascii}`;
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);
} }
return out;
} }
appendArray(arr1, arr2) { appendArray(a, b) {
const combined = new Uint8Array(arr1.length + arr2.length); const out = new Uint8Array(a.length + b.length);
combined.set(arr1); out.set(a);
combined.set(arr2, arr1.length); out.set(b, a.length);
return combined; return out;
}
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}`);
} }
inWaiting() { inWaiting() {
@@ -131,94 +106,125 @@ class Transport {
} }
slipWriter(data) { slipWriter(data) {
const outData = []; const out = [this.SLIP_END];
outData.push(0xc0); for (const b of data) {
for (let i = 0; i < data.length; i++) { if (b === this.SLIP_END) out.push(this.SLIP_ESC, this.SLIP_ESC_END);
if (data[i] === 0xdb) outData.push(0xdb, 0xdd); else if (b === this.SLIP_ESC) out.push(this.SLIP_ESC, this.SLIP_ESC_ESC);
else if (data[i] === 0xc0) outData.push(0xdb, 0xdc); else out.push(b);
else outData.push(data[i]);
} }
outData.push(0xc0); out.push(this.SLIP_END);
return new Uint8Array(outData); return new Uint8Array(out);
} }
async write(data) { async write(data) {
const outData = this.slipWriter(data); const out = this.slipReaderEnabled ? this.slipWriter(data) : data;
if (this.tracing) { 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) { async newRead(numBytes, timeout) {
const start = Date.now(); const start = Date.now();
while (this.buffer.length < numBytes && Date.now() - start < timeout) {
if (!this.serial.isOpened()) { while (this.buffer.length < numBytes) {
return null; if (!this.serial.isOpened()) return null;
} if (Date.now() - start > timeout) break;
await this.sleep(10); await this.sleep(5);
} }
const out = this.buffer.slice(0, numBytes); const out = this.buffer.slice(0, numBytes);
this.buffer = this.buffer.slice(numBytes); this.buffer = this.buffer.slice(numBytes);
return out; return out;
} }
async *read(timeout = 1000) { async *read(timeout = 1000) {
let partialPacket = null; let partial = null;
let isEscaping = false; let escaping = false;
const SLIP_END = 0xc0; let successfulSlip = false;
const SLIP_ESC = 0xdb;
const SLIP_ESC_END = 0xdc;
const SLIP_ESC_ESC = 0xdd;
while (true) { while (true) {
const data = await this.newRead(1, timeout); const chunk = await this.newRead(1, timeout);
if (!data || data.length === 0) break; 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]; const byte = chunk[0];
if (partialPacket === null) {
if (byte === SLIP_END) partialPacket = new Uint8Array(0); if (partial === null) {
} else if (isEscaping) { if (byte === this.SLIP_END) {
isEscaping = false; partial = new Uint8Array(0);
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;
} }
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 { } else {
partialPacket = this.appendArray(partialPacket, new Uint8Array([byte])); partial = this.appendArray(partial, new Uint8Array([byte]));
} }
} }
} }
detectPanicHandler(input) { detectPanicHandler(input) {
const guruMeditationRegex = const text = new TextDecoder().decode(input);
/G?uru Meditation Error: (?:Core \d panic'ed \(([a-zA-Z ]*)\))?/; const guru = /G?uru Meditation Error/;
const fatalExceptionRegex = const fatal = /F?atal exception \(\d+\)/;
/F?atal exception \(\d+\): (?:([a-zA-Z ]*)?.*epc)?/; if (guru.test(text) || fatal.test(text)) {
throw new Error('Guru Meditation Error detected');
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);
} }
} }
}
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; Web.SerialTransport = Transport;

File diff suppressed because one or more lines are too long