Skip to content

Commit

Permalink
add tracing for Transport class (#107)
Browse files Browse the repository at this point in the history
* add tracing for Transport class

fix lint issues

* update hex convert function

* fix lint

* update trace output

* test new hex convert

* fix trace format and chars

* fix lint issues

* fix slip write
  • Loading branch information
brianignacio5 authored Dec 4, 2023
1 parent 453962e commit d2d82cb
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 34 deletions.
1 change: 1 addition & 0 deletions examples/typescript/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ <h3> Program </h3>
</select>

<input class="btn btn-info btn-sm" type="button" id="connectButton" value="Connect" />
<input class="btn btn-info btn-sm" type="button" id="copyTraceButton" value="Copy Trace" />
<input class="btn btn-warning btn-sm" type="button" id="disconnectButton" value="Disconnect" />
<input class="btn btn-danger btn-sm" type="button" id="eraseButton" value="Erase Flash" />
<br>
Expand Down
16 changes: 13 additions & 3 deletions examples/typescript/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const baudrates = document.getElementById("baudrates") as HTMLSelectElement;
const connectButton = document.getElementById("connectButton") as HTMLButtonElement;
const traceButton = document.getElementById("copyTraceButton") as HTMLButtonElement;
const disconnectButton = document.getElementById("disconnectButton") as HTMLButtonElement;
const resetButton = document.getElementById("resetButton") as HTMLButtonElement;
const consoleStartButton = document.getElementById("consoleStartButton") as HTMLButtonElement;
Expand Down Expand Up @@ -34,6 +35,7 @@ let chip: string = null;
let esploader: ESPLoader;

disconnectButton.style.display = "none";
traceButton.style.display = "none";
eraseButton.style.display = "none";
consoleStopButton.style.display = "none";
filesDiv.style.display = "none";
Expand Down Expand Up @@ -77,7 +79,7 @@ const espLoaderTerminal = {
connectButton.onclick = async () => {
if (device === null) {
device = await navigator.serial.requestPort({});
transport = new Transport(device);
transport = new Transport(device, true);
}

try {
Expand All @@ -104,15 +106,22 @@ connectButton.onclick = async () => {
baudrates.style.display = "none";
connectButton.style.display = "none";
disconnectButton.style.display = "initial";
traceButton.style.display = "initial";
eraseButton.style.display = "initial";
filesDiv.style.display = "initial";
consoleDiv.style.display = "none";
};

traceButton.onclick = async () => {
if (transport) {
transport.returnTrace();
}
};

resetButton.onclick = async () => {
if (device === null) {
device = await navigator.serial.requestPort({});
transport = new Transport(device);
transport = new Transport(device, true);
}

await transport.setDTR(false);
Expand Down Expand Up @@ -207,6 +216,7 @@ disconnectButton.onclick = async () => {
baudrates.style.display = "initial";
connectButton.style.display = "initial";
disconnectButton.style.display = "none";
traceButton.style.display = "none";
eraseButton.style.display = "none";
lblConnTo.style.display = "none";
filesDiv.style.display = "none";
Expand All @@ -219,7 +229,7 @@ let isConsoleClosed = false;
consoleStartButton.onclick = async () => {
if (device === null) {
device = await navigator.serial.requestPort({});
transport = new Transport(device);
transport = new Transport(device, true);
}
lblConsoleFor.style.display = "block";
consoleStartButton.style.display = "none";
Expand Down
15 changes: 14 additions & 1 deletion src/esploader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export interface LoaderOptions {
* @type {boolean}
*/
debugLogging?: boolean;
enableTracing: boolean;
}

type FlashReadCallback = ((packet: Uint8Array, progress: number, totalSize: number) => void) | null;
Expand Down Expand Up @@ -270,13 +271,17 @@ export class ESPLoader {
this.terminal = options.terminal;
this.terminal.clean();
}
if (options.debugLogging) {
if (typeof options.debugLogging !== "undefined") {
this.debugLogging = options.debugLogging;
}
if (options.port) {
this.transport = new Transport(options.port);
}

if (typeof options.enableTracing !== "undefined") {
this.transport.tracing = options.enableTracing;
}

this.info("esptool.js");
this.info("Serial port " + this.transport.getInfo());
}
Expand Down Expand Up @@ -478,6 +483,14 @@ export class ESPLoader {
timeout = 3000,
): Promise<[number, Uint8Array]> {
if (op != null) {
if (this.transport.tracing) {
this.transport.trace(
`command op:0x${op.toString(16).padStart(2, "0")} data len=${data.length} wait_response=${
waitResponse ? 1 : 0
} timeout=${(timeout / 1000).toFixed(3)} data=${this.transport.hexConvert(data)}`,
);
}

const pkt = new Uint8Array(8 + data.length);
pkt[0] = 0x00;
pkt[1] = op;
Expand Down
117 changes: 87 additions & 30 deletions src/webserial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,18 @@ class Transport {
public slipReaderEnabled = false;
public leftOver = new Uint8Array(0);
public baudrate = 0;
private traceLog = "";
private lastTraceTime = Date.now();

constructor(public device: SerialPort) {}
constructor(public device: SerialPort, public tracing = false, enableSlipReader = true) {
this.slipReaderEnabled = enableSlipReader;
}

/**
* Request the serial device vendor ID and Product ID as string.
* @returns {string} Return the device VendorID and ProductID from SerialPortInfo as formatted string.
*/
getInfo() {
getInfo(): string {
const info = this.device.getInfo();
return info.usbVendorId && info.usbProductId
? `WebSerial VendorID 0x${info.usbVendorId.toString(16)} ProductID 0x${info.usbProductId.toString(16)}`
Expand All @@ -76,46 +80,80 @@ class Transport {

/**
* Request the serial device product id from SerialPortInfo.
* @returns {string} Return the product ID.
* @returns {number | undefined} Return the product ID.
*/
getPid() {
getPid(): number | undefined {
return this.device.getInfo().usbProductId;
}

/**
* Format received or sent data for tracing output.
* @param {string} message Message to format as trace line.
*/
trace(message: string) {
const delta = Date.now() - this.lastTraceTime;
const prefix = `TRACE ${delta.toFixed(3)}`;
const traceMessage = `${prefix} ${message}`;
console.log(traceMessage);
this.traceLog += traceMessage + "\n";
}

async returnTrace() {
try {
await navigator.clipboard.writeText(this.traceLog);
console.log("Text copied to clipboard!");
} catch (err) {
console.error("Failed to copy text:", err);
}
}

hexify(s: Uint8Array) {
return Array.from(s)
.map((byte) => byte.toString(16).padStart(2, "0"))
.join("")
.padEnd(16, " ");
}

hexConvert(uint8Array: 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);
}
}

/**
* Format data packet using the Serial Line Internet Protocol (SLIP).
* @param {Uint8Array} data Binary unsigned 8 bit array data to format.
* @returns {Uint8Array} Formatted unsigned 8 bit data array.
*/
slipWriter(data: Uint8Array) {
let countEsc = 0;
let i = 0,
j = 0;

for (i = 0; i < data.length; i++) {
if (data[i] === 0xc0 || data[i] === 0xdb) {
countEsc++;
}
}
const outData = new Uint8Array(2 + countEsc + data.length);
outData[0] = 0xc0;
j = 1;
for (i = 0; i < data.length; i++, j++) {
if (data[i] === 0xc0) {
outData[j++] = 0xdb;
outData[j] = 0xdc;
continue;
}
const outData = [];
outData.push(0xc0);
for (let i = 0; i < data.length; i++) {
if (data[i] === 0xdb) {
outData[j++] = 0xdb;
outData[j] = 0xdd;
continue;
outData.push(0xdb, 0xdd);
} else if (data[i] === 0xc0) {
outData.push(0xdb, 0xdc);
} else {
outData.push(data[i]);
}

outData[j] = data[i];
}
outData[j] = 0xc0;
return outData;
outData.push(0xc0);
return new Uint8Array(outData);
}

/**
Expand All @@ -127,6 +165,10 @@ class Transport {

if (this.device.writable) {
const writer = this.device.writable.getWriter();
if (this.tracing) {
console.log("Write bytes");
this.trace(`Write ${outData.length} bytes: ${this.hexConvert(outData)}`);
}
await writer.write(outData);
writer.releaseLock();
}
Expand Down Expand Up @@ -239,8 +281,19 @@ class Transport {
}
reader.releaseLock();
}

if (this.tracing) {
console.log("Read bytes");
this.trace(`Read ${packet.length} bytes: ${this.hexConvert(packet)}`);
}

if (this.slipReaderEnabled) {
return this.slipReader(packet);
const slipReaderResult = this.slipReader(packet);
if (this.tracing) {
console.log("Slip reader results");
this.trace(`Read ${slipReaderResult.length} bytes: ${this.hexConvert(slipReaderResult)}`);
}
return slipReaderResult;
}
return packet;
}
Expand Down Expand Up @@ -271,6 +324,10 @@ class Transport {
if (done) {
throw new Error("Timeout");
}
if (this.tracing) {
console.log("Raw Read bytes");
this.trace(`Read ${value.length} bytes: ${this.hexConvert(value)}`);
}
return value;
} finally {
if (timeout > 0) {
Expand Down

0 comments on commit d2d82cb

Please sign in to comment.