Skip to content

Commit e107099

Browse files
add reset functions (#100)
* add reset functions * fix lint * fix args types for custom reset
1 parent 66a109e commit e107099

File tree

2 files changed

+128
-29
lines changed

2 files changed

+128
-29
lines changed

src/esploader.ts

+4-29
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ESPError } from "./error";
22
import { Data, deflate, Inflate } from "pako";
33
import { Transport } from "./webserial";
44
import { ROM } from "./targets/rom";
5+
import { customReset, usbJTAGSerialReset } from "./reset";
56

67
async function magic2Chip(magic: number): Promise<ROM | null> {
78
switch (magic) {
@@ -296,36 +297,10 @@ export class ESPLoader {
296297
if (this.transport.get_pid() === this.USB_JTAG_SERIAL_PID) {
297298
// Custom reset sequence, which is required when the device
298299
// is connecting via its USB-JTAG-Serial peripheral
299-
await this.transport.setRTS(false);
300-
await this.transport.setDTR(false);
301-
await this._sleep(100);
302-
303-
await this.transport.setDTR(true);
304-
await this.transport.setRTS(false);
305-
await this._sleep(100);
306-
307-
await this.transport.setRTS(true);
308-
await this.transport.setDTR(false);
309-
await this.transport.setRTS(true);
310-
311-
await this._sleep(100);
312-
await this.transport.setRTS(false);
313-
await this.transport.setDTR(false);
300+
await usbJTAGSerialReset(this.transport);
314301
} else {
315-
await this.transport.setDTR(false);
316-
await this.transport.setRTS(true);
317-
await this._sleep(100);
318-
if (esp32r0_delay) {
319-
//await this._sleep(1200);
320-
await this._sleep(2000);
321-
}
322-
await this.transport.setDTR(true);
323-
await this.transport.setRTS(false);
324-
if (esp32r0_delay) {
325-
//await this._sleep(400);
326-
}
327-
await this._sleep(50);
328-
await this.transport.setDTR(false);
302+
const strSequence = esp32r0_delay ? "D0|R1|W100|W2000|D1|R0|W50|D0" : "D0|R1|W100|D1|R0|W50|D0";
303+
await customReset(this.transport, strSequence);
329304
}
330305
}
331306
let i = 0;

src/reset.ts

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { Transport } from "./webserial";
2+
3+
const DEFAULT_RESET_DELAY = 50;
4+
5+
function sleep(ms: number): Promise<void> {
6+
return new Promise((resolve) => setTimeout(resolve, ms));
7+
}
8+
9+
export async function classicReset(transport: Transport, resetDelay = DEFAULT_RESET_DELAY) {
10+
await transport.setDTR(false);
11+
await transport.setRTS(true);
12+
await sleep(100);
13+
await transport.setDTR(true);
14+
await transport.setRTS(false);
15+
await sleep(resetDelay);
16+
await transport.setDTR(false);
17+
}
18+
19+
export async function usbJTAGSerialReset(transport: Transport) {
20+
await transport.setRTS(false);
21+
await transport.setDTR(false);
22+
await sleep(100);
23+
24+
await transport.setDTR(true);
25+
await transport.setRTS(false);
26+
await sleep(100);
27+
28+
await transport.setRTS(true);
29+
await transport.setDTR(false);
30+
await transport.setRTS(true);
31+
32+
await sleep(100);
33+
await transport.setRTS(false);
34+
await transport.setDTR(false);
35+
}
36+
37+
export async function hardReset(transport: Transport, usingUsbOtg = false) {
38+
if (usingUsbOtg) {
39+
await sleep(200);
40+
await transport.setRTS(false);
41+
await sleep(200);
42+
} else {
43+
await sleep(100);
44+
await transport.setRTS(false);
45+
}
46+
}
47+
48+
type CmdsArgsTypes = {
49+
D: boolean;
50+
R: boolean;
51+
W: number;
52+
};
53+
54+
export function validateCustomResetStringSequence(seqStr: string): boolean {
55+
const commands: (keyof CmdsArgsTypes)[] = ["D", "R", "W"];
56+
57+
const commandsList = seqStr.split("|");
58+
59+
for (const cmd of commandsList) {
60+
const code = cmd[0];
61+
const arg = cmd.slice(1);
62+
63+
if (!commands.includes(code as keyof CmdsArgsTypes)) {
64+
return false; // Invalid command code
65+
}
66+
67+
if (code === "D" || code === "R") {
68+
if (arg !== "0" && arg !== "1") {
69+
return false; // Invalid argument for D and R commands
70+
}
71+
} else if (code === "W") {
72+
const delay = parseInt(arg);
73+
if (isNaN(delay) || delay <= 0) {
74+
return false; // Invalid argument for W command
75+
}
76+
}
77+
}
78+
return true; // All commands are valid
79+
}
80+
81+
/**
82+
* Custom reset strategy defined with a string.
83+
*
84+
* The sequenceString input string consists of individual commands divided by "|".
85+
*
86+
* Commands (e.g. R0) are defined by a code (R) and an argument (0).
87+
*
88+
* The commands are:
89+
*
90+
* D: setDTR - 1=True / 0=False
91+
*
92+
* R: setRTS - 1=True / 0=False
93+
*
94+
* W: Wait (time delay) - positive integer number (miliseconds)
95+
*
96+
* "D0|R1|W100|D1|R0|W50|D0" represents the classic reset strategy
97+
*/
98+
export async function customReset(transport: Transport, sequenceString: string) {
99+
const resetDictionary: { [K in keyof CmdsArgsTypes]: (arg: CmdsArgsTypes[K]) => Promise<void> } = {
100+
D: async (arg: boolean) => await transport.setDTR(arg),
101+
R: async (arg: boolean) => await transport.setRTS(arg),
102+
W: async (delay: number) => await sleep(delay),
103+
};
104+
try {
105+
const isValidSequence = validateCustomResetStringSequence(sequenceString);
106+
if (!isValidSequence) {
107+
return;
108+
}
109+
const cmds = sequenceString.split("|");
110+
for (const cmd of cmds) {
111+
const cmdKey = cmd[0];
112+
const cmdVal = cmd.slice(1);
113+
if (cmdKey === "W") {
114+
await resetDictionary["W"](Number(cmdVal));
115+
} else if (cmdKey === "D" || cmdKey === "R") {
116+
await resetDictionary[cmdKey as "D" | "R"](cmdVal === "1");
117+
}
118+
}
119+
} catch (error) {
120+
throw new Error("Invalid custom reset sequence");
121+
}
122+
}
123+
124+
export default { classicReset, customReset, hardReset, usbJTAGSerialReset, validateCustomResetStringSequence };

0 commit comments

Comments
 (0)