Skip to content

Commit 260e5ea

Browse files
committed
further refactoring of transport and esploader
1 parent c033caf commit 260e5ea

9 files changed

Lines changed: 355 additions & 284 deletions

File tree

src/esploader.ts

Lines changed: 113 additions & 162 deletions
Large diffs are not rendered by default.

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export { IEspLoaderTerminal, ESPLoader, FlashOptions, LoaderOptions } from "./esploader";
22
export { classicReset, customReset, hardReset, usbJTAGSerialReset, validateCustomResetStringSequence } from "./reset";
33
export { ROM } from "./targets/rom";
4-
export { AbstractTransport, ISerialOptions } from "./transport/ITransport";
4+
export { AbstractTransport, ISerialOptions } from "./transport/AbstractTransport";
55
export { SerialOptions, WebSerialTransport } from "./transport/WebSerialTransport";

src/reset.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AbstractTransport } from "./transport/ITransport";
1+
import { AbstractTransport } from "./transport/AbstractTransport";
22

33
const DEFAULT_RESET_DELAY = 50;
44

src/transport/AbstractTransport.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* Options for device connection.
3+
* @interface ISerialOptions
4+
*/
5+
export interface ISerialOptions {
6+
/**
7+
* A positive, non-zero value indicating the baud rate at which serial communication should be established.
8+
* @type {number}
9+
*/
10+
baudRate: number;
11+
}
12+
13+
/**
14+
* Template to define Transport class which can be consumed by the ESPLoader.
15+
* A Webserial reference implementation is found at src/transport/WebSerialTransport.ts
16+
*/
17+
export abstract class AbstractTransport {
18+
public abstract tracing: boolean;
19+
public abstract slipReaderEnabled: boolean;
20+
21+
/**
22+
* Request the serial device information as string.
23+
* @returns {string} Return the serial device information as formatted string.
24+
*/
25+
public abstract getInfo(): string;
26+
27+
/**
28+
* Request the serial device product id.
29+
* @returns {number | undefined} Return the product ID.
30+
*/
31+
public abstract getPID(): number | undefined;
32+
33+
/**
34+
* Format received or sent data for tracing output.
35+
* @param {string} message Message to format as trace line.
36+
*/
37+
public abstract trace(message: string): void;
38+
39+
/**
40+
* Write binary data to device.
41+
* @param {Uint8Array} data 8 bit unsigned data array to write to device.
42+
*/
43+
public abstract write(data: Uint8Array): Promise<void>;
44+
45+
/**
46+
* Read from serial device.
47+
* @param {number} timeout Read timeout number
48+
* @param {number} minData Minimum packet array length
49+
* @returns {Promise<Uint8Array>} 8 bit unsigned data array read from device.
50+
*/
51+
public abstract read(timeout?: number, minData?: number): Promise<Uint8Array>;
52+
53+
/**
54+
* Read from serial device without formatting.
55+
* @param {number} timeout Read timeout in milliseconds (ms)
56+
* @returns {Promise<Uint8Array>} 8 bit unsigned data array read from device.
57+
*/
58+
public abstract rawRead(timeout?: number): Promise<Uint8Array>;
59+
60+
/**
61+
* Send the RequestToSend (RTS) signal to given state
62+
* # True for EN=LOW, chip in reset and False EN=HIGH, chip out of reset
63+
* @param {boolean} state Boolean state to set the signal
64+
*/
65+
public abstract setRTS(state: boolean): Promise<void>;
66+
67+
/**
68+
* Send the dataTerminalReady (DTS) signal to given state
69+
* # True for IO0=LOW, chip in reset and False IO0=HIGH
70+
* @param {boolean} state Boolean state to set the signal
71+
*/
72+
public abstract setDTR(state: boolean): Promise<void>;
73+
74+
/**
75+
* Connect to serial device using the Webserial open method.
76+
* @param {SerialOptions} serialOptions Serial Options for WebUSB SerialPort class.
77+
*/
78+
public abstract connect(serialOptions: ISerialOptions): Promise<void>;
79+
80+
/**
81+
* Disconnect from serial device by running SerialPort.close() after streams unlock.
82+
*/
83+
public abstract disconnect(): Promise<void>;
84+
}

src/transport/ITransport.ts

Lines changed: 0 additions & 50 deletions
This file was deleted.

src/transport/WebSerialTransport.ts

Lines changed: 14 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
/* global SerialPort, ParityType, FlowControlType */
22

3-
import { AbstractTransport, ISerialOptions } from "./ITransport";
3+
import { AbstractTransport, ISerialOptions } from "./AbstractTransport";
4+
import { hexConvert } from "../utils/hex";
5+
import { appendArray } from "../utils/convert";
6+
import { slipWriter } from "../utils/slip";
47

58
/**
69
* Options for device serialPort.
@@ -86,6 +89,9 @@ export class WebSerialTransport implements AbstractTransport {
8689
this.traceLog += traceMessage + "\n";
8790
}
8891

92+
/**
93+
* Return the whole trace output to the user clipboard.
94+
*/
8995
async returnTrace() {
9096
try {
9197
await navigator.clipboard.writeText(this.traceLog);
@@ -95,86 +101,24 @@ export class WebSerialTransport implements AbstractTransport {
95101
}
96102
}
97103

98-
hexify(s: Uint8Array) {
99-
return Array.from(s)
100-
.map((byte) => byte.toString(16).padStart(2, "0"))
101-
.join("")
102-
.padEnd(16, " ");
103-
}
104-
105-
hexConvert(uint8Array: Uint8Array, autoSplit = true) {
106-
if (autoSplit && uint8Array.length > 16) {
107-
let result = "";
108-
let s = uint8Array;
109-
110-
while (s.length > 0) {
111-
const line = s.slice(0, 16);
112-
const asciiLine = String.fromCharCode(...line)
113-
.split("")
114-
.map((c) => (c === " " || (c >= " " && c <= "~" && c !== " ") ? c : "."))
115-
.join("");
116-
s = s.slice(16);
117-
result += `\n ${this.hexify(line.slice(0, 8))} ${this.hexify(line.slice(8))} | ${asciiLine}`;
118-
}
119-
120-
return result;
121-
} else {
122-
return this.hexify(uint8Array);
123-
}
124-
}
125-
126-
/**
127-
* Format data packet using the Serial Line Internet Protocol (SLIP).
128-
* @param {Uint8Array} data Binary unsigned 8 bit array data to format.
129-
* @returns {Uint8Array} Formatted unsigned 8 bit data array.
130-
*/
131-
slipWriter(data: Uint8Array) {
132-
const outData = [];
133-
outData.push(0xc0);
134-
for (let i = 0; i < data.length; i++) {
135-
if (data[i] === 0xdb) {
136-
outData.push(0xdb, 0xdd);
137-
} else if (data[i] === 0xc0) {
138-
outData.push(0xdb, 0xdc);
139-
} else {
140-
outData.push(data[i]);
141-
}
142-
}
143-
outData.push(0xc0);
144-
return new Uint8Array(outData);
145-
}
146-
147104
/**
148105
* Write binary data to device using the WebSerial device writable stream.
149106
* @param {Uint8Array} data 8 bit unsigned data array to write to device.
150107
*/
151108
async write(data: Uint8Array) {
152-
const outData = this.slipWriter(data);
109+
const outData = slipWriter(data);
153110

154111
if (this.device.writable) {
155112
const writer = this.device.writable.getWriter();
156113
if (this.tracing) {
157114
console.log("Write bytes");
158-
this.trace(`Write ${outData.length} bytes: ${this.hexConvert(outData)}`);
115+
this.trace(`Write ${outData.length} bytes: ${hexConvert(outData)}`);
159116
}
160117
await writer.write(outData);
161118
writer.releaseLock();
162119
}
163120
}
164121

165-
/**
166-
* Concatenate buffer2 to buffer1 and return the resulting ArrayBuffer.
167-
* @param {ArrayBuffer} buffer1 First buffer to concatenate.
168-
* @param {ArrayBuffer} buffer2 Second buffer to concatenate.
169-
* @returns {ArrayBuffer} Result Array buffer.
170-
*/
171-
_appendBuffer(buffer1: ArrayBuffer, buffer2: ArrayBuffer) {
172-
const tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
173-
tmp.set(new Uint8Array(buffer1), 0);
174-
tmp.set(new Uint8Array(buffer2), buffer1.byteLength);
175-
return tmp.buffer;
176-
}
177-
178122
/**
179123
* Take a data array and return the first well formed packet after
180124
* replacing the escape sequence. Reads at least 8 bytes.
@@ -260,7 +204,7 @@ export class WebSerialTransport implements AbstractTransport {
260204
this.leftOver = packet;
261205
throw new Error("Timeout");
262206
}
263-
const p = new Uint8Array(this._appendBuffer(packet.buffer, value.buffer));
207+
const p = appendArray(packet, value);
264208
packet = p;
265209
} while (packet.length < minData);
266210
} finally {
@@ -272,14 +216,14 @@ export class WebSerialTransport implements AbstractTransport {
272216

273217
if (this.tracing) {
274218
console.log("Read bytes");
275-
this.trace(`Read ${packet.length} bytes: ${this.hexConvert(packet)}`);
219+
this.trace(`Read ${packet.length} bytes: ${hexConvert(packet)}`);
276220
}
277221

278222
if (this.slipReaderEnabled) {
279223
const slipReaderResult = this.slipReader(packet);
280224
if (this.tracing) {
281225
console.log("Slip reader results");
282-
this.trace(`Read ${slipReaderResult.length} bytes: ${this.hexConvert(slipReaderResult)}`);
226+
this.trace(`Read ${slipReaderResult.length} bytes: ${hexConvert(slipReaderResult)}`);
283227
}
284228
return slipReaderResult;
285229
}
@@ -314,7 +258,7 @@ export class WebSerialTransport implements AbstractTransport {
314258
}
315259
if (this.tracing) {
316260
console.log("Raw Read bytes");
317-
this.trace(`Read ${value.length} bytes: ${this.hexConvert(value)}`);
261+
this.trace(`Read ${value.length} bytes: ${hexConvert(value)}`);
318262
}
319263
return value;
320264
} finally {
@@ -352,7 +296,7 @@ export class WebSerialTransport implements AbstractTransport {
352296

353297
/**
354298
* Connect to serial device using the Webserial open method.
355-
* @param {SerialOptions} serialOptions Serial Options for WebUSB SerialPort class.
299+
* @param {SerialOptions} serialOptions Serial Options for ESP Loader class.
356300
*/
357301
async connect(serialOptions: SerialOptions) {
358302
await this.device.open({

src/utils/convert.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* Concatenate array 2 to array 1 and return the resulting UInt8Array.
3+
* @param {Uint8Array} array1 First array to concatenate.
4+
* @param {Uint8Array} array2 Second array to concatenate.
5+
* @returns {Uint8Array} Result UInt8Array.
6+
*/
7+
export function appendArray(array1: Uint8Array, array2: Uint8Array): Uint8Array {
8+
const result = new Uint8Array(array1.length + array2.length);
9+
result.set(array1, 0);
10+
result.set(array2, array1.length);
11+
return result;
12+
}
13+
14+
/**
15+
* Convert short integer to byte array
16+
* @param {number} i - Number to convert.
17+
* @returns {Uint8Array} Byte array.
18+
*/
19+
export function shortToBytearray(i: number): Uint8Array {
20+
return new Uint8Array([i & 0xff, (i >> 8) & 0xff]);
21+
}
22+
23+
/**
24+
* Convert an integer to byte array
25+
* @param {number} i - Number to convert.
26+
* @returns {Uint8Array} Array of byte from interger
27+
*/
28+
export function intToByteArray(i: number): Uint8Array {
29+
return new Uint8Array([i & 0xff, (i >> 8) & 0xff, (i >> 16) & 0xff, (i >> 24) & 0xff]);
30+
}
31+
32+
/**
33+
* Convert a byte array to short integer.
34+
* @param {number} i - Number to convert.
35+
* @param {number} j - Number to convert.
36+
* @returns {number} Return a short integer number.
37+
*/
38+
export function byteArrayToShort(i: number, j: number): number {
39+
return i | (j >> 8);
40+
}
41+
42+
/**
43+
* Convert a byte array to integer.
44+
* @param {number} i - Number to convert.
45+
* @param {number} j - Number to convert.
46+
* @param {number} k - Number to convert.
47+
* @param {number} l - Number to convert.
48+
* @returns {number} Return a integer number.
49+
*/
50+
export function byteArrayToInt(i: number, j: number, k: number, l: number): number {
51+
return i | (j << 8) | (k << 16) | (l << 24);
52+
}
53+
54+
/**
55+
* Convert a unsigned 8 bit integer array to byte string.
56+
* @param {Uint8Array} u8Array - magic hex number to select ROM.
57+
* @returns {string} Return the equivalent string.
58+
*/
59+
export function ui8ToBstr(u8Array: Uint8Array): string {
60+
let bStr = "";
61+
for (let i = 0; i < u8Array.length; i++) {
62+
bStr += String.fromCharCode(u8Array[i]);
63+
}
64+
return bStr;
65+
}
66+
67+
/**
68+
* Convert a byte string to unsigned 8 bit integer array.
69+
* @param {string} bStr - binary string input
70+
* @returns {Uint8Array} Return a 8 bit unsigned integer array.
71+
*/
72+
export function bstrToUi8(bStr: string): Uint8Array {
73+
const u8Array = new Uint8Array(bStr.length);
74+
for (let i = 0; i < bStr.length; i++) {
75+
u8Array[i] = bStr.charCodeAt(i);
76+
}
77+
return u8Array;
78+
}

0 commit comments

Comments
 (0)