tasmota-webserial-esptool 6.1.0 → 6.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/build_upload.yml +4 -5
- package/.github/workflows/ci.yml +2 -1
- package/README.md +1 -5
- package/dist/const.js +2 -0
- package/dist/esp_loader.js +2 -2
- package/dist/stubs/esp32.json +2 -2
- package/dist/stubs/esp32c2.json +2 -2
- package/dist/stubs/esp32c3.json +2 -2
- package/dist/stubs/esp32c6.json +2 -2
- package/dist/stubs/esp32h2.json +2 -2
- package/dist/stubs/esp32s2.json +2 -2
- package/dist/stubs/esp32s3.json +4 -4
- package/dist/stubs/esp8266.json +7 -1
- package/dist/web/esp32-165a50ff.js +1 -0
- package/{js/modules/esp32c2-f0222390.js → dist/web/esp32c2-895e50a1.js} +1 -1
- package/dist/web/esp32c3-dc0915b5.js +1 -0
- package/dist/web/esp32c6-2dda1f55.js +1 -0
- package/dist/web/esp32h2-064ce7cf.js +1 -0
- package/dist/web/esp32s2-ffc43e14.js +1 -0
- package/dist/web/esp32s3-857df8a8.js +1 -0
- package/dist/web/esp8266-a8241797.js +1 -0
- package/dist/web/index.js +1 -1
- package/index.html +1 -1
- package/js/modules/esp32-165a50ff.js +1 -0
- package/{dist/web/esp32c2-f0222390.js → js/modules/esp32c2-895e50a1.js} +1 -1
- package/js/modules/esp32c3-dc0915b5.js +1 -0
- package/js/modules/esp32c6-2dda1f55.js +1 -0
- package/js/modules/esp32h2-064ce7cf.js +1 -0
- package/js/modules/esp32s2-ffc43e14.js +1 -0
- package/js/modules/esp32s3-857df8a8.js +1 -0
- package/js/modules/esp8266-a8241797.js +1 -0
- package/js/modules/esptool.js +1 -1
- package/js/script.js +2 -2
- package/package.json +9 -9
- package/rollup.config.js +1 -1
- package/script/build +1 -2
- package/src/const.ts +4 -2
- package/src/esp_loader.ts +51 -51
- package/src/stubs/esp32.json +2 -2
- package/src/stubs/esp32c2.json +2 -2
- package/src/stubs/esp32c3.json +3 -3
- package/src/stubs/esp32c6.json +3 -3
- package/src/stubs/esp32h2.json +3 -3
- package/src/stubs/esp32s2.json +3 -3
- package/src/stubs/esp32s3.json +5 -5
- package/src/stubs/esp8266.json +7 -1
- package/dist/web/esp32-d51f885c.js +0 -1
- package/dist/web/esp32c3-9f5fd05b.js +0 -1
- package/dist/web/esp32c6-e911f438.js +0 -1
- package/dist/web/esp32h2-19e099dc.js +0 -1
- package/dist/web/esp32s2-da1a4fa1.js +0 -1
- package/dist/web/esp32s3-d79eec99.js +0 -1
- package/dist/web/esp8266-144419c0.js +0 -1
- package/js/esptool.js +0 -1396
- package/js/modules/esp32-d51f885c.js +0 -1
- package/js/modules/esp32c3-9f5fd05b.js +0 -1
- package/js/modules/esp32c6-e911f438.js +0 -1
- package/js/modules/esp32h2-19e099dc.js +0 -1
- package/js/modules/esp32s2-da1a4fa1.js +0 -1
- package/js/modules/esp32s3-d79eec99.js +0 -1
- package/js/modules/esp8266-144419c0.js +0 -1
- package/script/stubgen.py +0 -47
- package/stubs/esp32.json +0 -7
- package/stubs/esp32c2.json +0 -7
- package/stubs/esp32c3.json +0 -7
- package/stubs/esp32c6.json +0 -7
- package/stubs/esp32h2.json +0 -7
- package/stubs/esp32s2.json +0 -7
- package/stubs/esp32s3.json +0 -7
- package/stubs/esp8266.json +0 -7
package/js/esptool.js
DELETED
|
@@ -1,1396 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
let port;
|
|
4
|
-
let reader;
|
|
5
|
-
let inputStream;
|
|
6
|
-
let outputStream;
|
|
7
|
-
let inputBuffer = [];
|
|
8
|
-
|
|
9
|
-
const esp8266FlashSizes = {
|
|
10
|
-
"512KB": 0x00,
|
|
11
|
-
"256KB": 0x10,
|
|
12
|
-
"1MB": 0x20,
|
|
13
|
-
"2MB": 0x30,
|
|
14
|
-
"4MB": 0x40,
|
|
15
|
-
"2MB-c1": 0x50,
|
|
16
|
-
"4MB-c1": 0x60,
|
|
17
|
-
"8MB": 0x80,
|
|
18
|
-
"16MB": 0x90,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const esp32FlashSizes = {
|
|
22
|
-
"1MB": 0x00,
|
|
23
|
-
"2MB": 0x10,
|
|
24
|
-
"4MB": 0x20,
|
|
25
|
-
"8MB": 0x30,
|
|
26
|
-
"16MB": 0x40,
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const flashMode = {
|
|
30
|
-
qio: 0,
|
|
31
|
-
qout: 1,
|
|
32
|
-
dio: 2,
|
|
33
|
-
dout: 3,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const flashFreq = {
|
|
37
|
-
"40m": 0,
|
|
38
|
-
"80m": 0xf,
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
// Defaults
|
|
42
|
-
// Flash Frequency: 40m
|
|
43
|
-
// Flash Mode: qio
|
|
44
|
-
// Flash Size: 1MB
|
|
45
|
-
|
|
46
|
-
const ESP_ROM_BAUD = 115200;
|
|
47
|
-
const FLASH_WRITE_SIZE = 0x400;
|
|
48
|
-
const STUBLOADER_FLASH_WRITE_SIZE = 0x4000;
|
|
49
|
-
const FLASH_SECTOR_SIZE = 0x1000; // Flash sector size, minimum unit of erase.
|
|
50
|
-
|
|
51
|
-
const SYNC_PACKET = toByteArray(
|
|
52
|
-
"\x07\x07\x12 UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"
|
|
53
|
-
);
|
|
54
|
-
const CHIP_DETECT_MAGIC_REG_ADDR = 0x40001000;
|
|
55
|
-
const ESP8266 = 0x8266;
|
|
56
|
-
const ESP32 = 0x32;
|
|
57
|
-
const ESP32S2 = 0x3252;
|
|
58
|
-
const ESP32S3 = 0x3253;
|
|
59
|
-
const ESP32C3 = 0x32c3;
|
|
60
|
-
|
|
61
|
-
// Commands supported by ESP8266 ROM bootloader
|
|
62
|
-
const ESP_FLASH_BEGIN = 0x02;
|
|
63
|
-
const ESP_FLASH_DATA = 0x03;
|
|
64
|
-
const ESP_FLASH_END = 0x04;
|
|
65
|
-
const ESP_MEM_BEGIN = 0x05;
|
|
66
|
-
const ESP_MEM_END = 0x06;
|
|
67
|
-
const ESP_MEM_DATA = 0x07;
|
|
68
|
-
const ESP_SYNC = 0x08;
|
|
69
|
-
const ESP_WRITE_REG = 0x09;
|
|
70
|
-
const ESP_READ_REG = 0x0a;
|
|
71
|
-
|
|
72
|
-
// Some comands supported by ESP32 ROM bootloader (or -8266 w/ stub)
|
|
73
|
-
const ESP_SPI_SET_PARAMS = 0x0b;
|
|
74
|
-
const ESP_SPI_ATTACH = 0x0d;
|
|
75
|
-
const ESP_READ_FLASH_SLOW = 0x0e; // ROM only, much slower than the stub flash read
|
|
76
|
-
const ESP_CHANGE_BAUDRATE = 0x0f;
|
|
77
|
-
const ESP_FLASH_DEFL_BEGIN = 0x10;
|
|
78
|
-
const ESP_FLASH_DEFL_DATA = 0x11;
|
|
79
|
-
const ESP_FLASH_DEFL_END = 0x12;
|
|
80
|
-
const ESP_SPI_FLASH_MD5 = 0x13;
|
|
81
|
-
|
|
82
|
-
// Commands supported by ESP32-S2/S3/C3/C6 ROM bootloader only
|
|
83
|
-
const ESP_GET_SECURITY_INFO = 0x14;
|
|
84
|
-
|
|
85
|
-
// Some commands supported by stub only
|
|
86
|
-
const ESP_ERASE_FLASH = 0xd0;
|
|
87
|
-
const ESP_ERASE_REGION = 0xd1;
|
|
88
|
-
const ESP_READ_FLASH = 0xd2;
|
|
89
|
-
const ESP_RUN_USER_CODE = 0xd3;
|
|
90
|
-
|
|
91
|
-
// Response code(s) sent by ROM
|
|
92
|
-
const ROM_INVALID_RECV_MSG = 0x05;
|
|
93
|
-
|
|
94
|
-
// Initial state for the checksum routine
|
|
95
|
-
const ESP_CHECKSUM_MAGIC = 0xef;
|
|
96
|
-
|
|
97
|
-
const UART_DATE_REG_ADDR = 0x60000078;
|
|
98
|
-
|
|
99
|
-
const USB_RAM_BLOCK = 0x800;
|
|
100
|
-
const ESP_RAM_BLOCK = 0x1800;
|
|
101
|
-
|
|
102
|
-
// Timeouts
|
|
103
|
-
const DEFAULT_TIMEOUT = 3000;
|
|
104
|
-
const CHIP_ERASE_TIMEOUT = 120000; // timeout for full chip erase in ms
|
|
105
|
-
const MAX_TIMEOUT = CHIP_ERASE_TIMEOUT * 2; // longest any command can run in ms
|
|
106
|
-
const SYNC_TIMEOUT = 100; // timeout for syncing with bootloader in ms
|
|
107
|
-
const ERASE_REGION_TIMEOUT_PER_MB = 30000; // timeout (per megabyte) for erasing a region in ms
|
|
108
|
-
const MEM_END_ROM_TIMEOUT = 500;
|
|
109
|
-
|
|
110
|
-
const supportedChips = {
|
|
111
|
-
ESP8266: {
|
|
112
|
-
chipId: ESP8266,
|
|
113
|
-
chipName: "ESP8266EX",
|
|
114
|
-
magicVal: [0xfff0c101],
|
|
115
|
-
baseFuseAddr: 0x3ff00050,
|
|
116
|
-
macFuseAddr: 0x3ff00050,
|
|
117
|
-
stubFile: "esp8266",
|
|
118
|
-
spiRegBase: 0x60000200,
|
|
119
|
-
spiUsrOffs: 0x1c,
|
|
120
|
-
spiUsr1Offs: 0x20,
|
|
121
|
-
spiUsr2Offs: 0x24,
|
|
122
|
-
spiMosiDlenOffs: null,
|
|
123
|
-
spiMisoDlenOffs: null,
|
|
124
|
-
spiW0Offs: 0x40,
|
|
125
|
-
},
|
|
126
|
-
ESP32: {
|
|
127
|
-
chipId: ESP32,
|
|
128
|
-
chipName: "ESP32",
|
|
129
|
-
magicVal: [0x00f01d83],
|
|
130
|
-
baseFuseAddr: 0x3ff5a000,
|
|
131
|
-
macFuseAddr: 0x3ff5a000,
|
|
132
|
-
stubFile: "esp32",
|
|
133
|
-
spiRegBase: 0x3ff42000,
|
|
134
|
-
spiUsrOffs: 0x1c,
|
|
135
|
-
spiUsr1Offs: 0x20,
|
|
136
|
-
spiUsr2Offs: 0x24,
|
|
137
|
-
spiMosiDlenOffs: 0x28,
|
|
138
|
-
spiMisoDlenOffs: 0x2c,
|
|
139
|
-
spiW0Offs: 0x80,
|
|
140
|
-
},
|
|
141
|
-
ESP32S2: {
|
|
142
|
-
chipId: ESP32S2,
|
|
143
|
-
chipName: "ESP32-S2",
|
|
144
|
-
magicVal: [0x000007c6],
|
|
145
|
-
baseFuseAddr: 0x3f41a000,
|
|
146
|
-
macFuseAddr: 0x3f41a044,
|
|
147
|
-
stubFile: "esp32s2",
|
|
148
|
-
spiRegBase: 0x3f402000,
|
|
149
|
-
spiUsrOffs: 0x18,
|
|
150
|
-
spiUsr1Offs: 0x1c,
|
|
151
|
-
spiUsr2Offs: 0x20,
|
|
152
|
-
spiMosiDlenOffs: 0x24,
|
|
153
|
-
spiMisoDlenOffs: 0x28,
|
|
154
|
-
spiW0Offs: 0x58,
|
|
155
|
-
},
|
|
156
|
-
ESP32S3: {
|
|
157
|
-
chipId: ESP32S3,
|
|
158
|
-
chipName: "ESP32-S3",
|
|
159
|
-
magicVal: [0x9],
|
|
160
|
-
baseFuseAddr: 0x60007000,
|
|
161
|
-
macFuseAddr: 0x60007044,
|
|
162
|
-
stubFile: "esp32s3",
|
|
163
|
-
spiRegBase: 0x60002000,
|
|
164
|
-
spiUsrOffs: 0x18,
|
|
165
|
-
spiUsr1Offs: 0x1c,
|
|
166
|
-
spiUsr2Offs: 0x20,
|
|
167
|
-
spiMosiDlenOffs: 0x24,
|
|
168
|
-
spiMisoDlenOffs: 0x28,
|
|
169
|
-
spiW0Offs: 0x58,
|
|
170
|
-
},
|
|
171
|
-
ESP32C3: {
|
|
172
|
-
chipId: ESP32C3,
|
|
173
|
-
chipName: "ESP32-C3",
|
|
174
|
-
magicVal: [0x6921506f, 0x1b31506f],
|
|
175
|
-
baseFuseAddr: 0x60008800,
|
|
176
|
-
macFuseAddr: 0x60008800 + 0x044,
|
|
177
|
-
stubFile: "esp32c3",
|
|
178
|
-
spiRegBase: 0x60002000,
|
|
179
|
-
spiUsrOffs: 0x18,
|
|
180
|
-
spiUsr1Offs: 0x1c,
|
|
181
|
-
spiUsr2Offs: 0x20,
|
|
182
|
-
spiMosiDlenOffs: 0x24,
|
|
183
|
-
spiMisoDlenOffs: 0x28,
|
|
184
|
-
spiW0Offs: 0x58,
|
|
185
|
-
},
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
class EspLoader {
|
|
189
|
-
constructor(params) {
|
|
190
|
-
this._chipfamily = null;
|
|
191
|
-
this.readTimeout = 3000; // Arbitrary number for now. This should be set more dynamically in the command() function
|
|
192
|
-
this._efuses = new Array(4).fill(0);
|
|
193
|
-
this._flashsize = 4 * 1024 * 1024;
|
|
194
|
-
if (this.isFunction(params.updateProgress)) {
|
|
195
|
-
this.updateProgress = params.updateProgress;
|
|
196
|
-
} else {
|
|
197
|
-
this.updateProgress = null;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (this.isFunction(params.logMsg)) {
|
|
201
|
-
this.logMsg = params.logMsg;
|
|
202
|
-
} else {
|
|
203
|
-
this.logMsg = console.log;
|
|
204
|
-
}
|
|
205
|
-
this.debug = params.debug;
|
|
206
|
-
if (this.isFunction(params.debugMsg)) {
|
|
207
|
-
this._debugMsg = params.debugMsg;
|
|
208
|
-
} else {
|
|
209
|
-
this._debugMsg = this.logMsg();
|
|
210
|
-
}
|
|
211
|
-
this.IS_STUB = false;
|
|
212
|
-
this.syncStubDetected = false;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
isFunction(functionObj) {
|
|
216
|
-
return functionObj && {}.toString.call(functionObj) === "[object Function]";
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
toHex(value, size = 2) {
|
|
220
|
-
return "0x" + value.toString(16).toUpperCase().padStart(size, "0");
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
getChromeVersion() {
|
|
224
|
-
let raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
|
|
225
|
-
|
|
226
|
-
return raw ? parseInt(raw[2], 10) : false;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* @name slipEncode
|
|
231
|
-
* Take an array buffer and return back a new array where
|
|
232
|
-
* 0xdb is replaced with 0xdb 0xdd and 0xc0 is replaced with 0xdb 0xdc
|
|
233
|
-
*/
|
|
234
|
-
slipEncode(buffer) {
|
|
235
|
-
let encoded = [0xc0];
|
|
236
|
-
for (let byte of buffer) {
|
|
237
|
-
if (byte == 0xdb) {
|
|
238
|
-
encoded = encoded.concat([0xdb, 0xdd]);
|
|
239
|
-
} else if (byte == 0xc0) {
|
|
240
|
-
encoded = encoded.concat([0xdb, 0xdc]);
|
|
241
|
-
} else {
|
|
242
|
-
encoded.push(byte);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
encoded.push(0xc0);
|
|
246
|
-
return encoded;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* @name macAddr
|
|
251
|
-
* The MAC address burned into the OTP memory of the ESP chip
|
|
252
|
-
*/
|
|
253
|
-
macAddr() {
|
|
254
|
-
let macAddr = new Array(6).fill(0);
|
|
255
|
-
let mac0 = this._efuses[0];
|
|
256
|
-
let mac1 = this._efuses[1];
|
|
257
|
-
let mac2 = this._efuses[2];
|
|
258
|
-
let mac3 = this._efuses[3];
|
|
259
|
-
let oui;
|
|
260
|
-
if (this._chipfamily == ESP8266) {
|
|
261
|
-
if (mac3 != 0) {
|
|
262
|
-
oui = [(mac3 >> 16) & 0xff, (mac3 >> 8) & 0xff, mac3 & 0xff];
|
|
263
|
-
} else if (((mac1 >> 16) & 0xff) == 0) {
|
|
264
|
-
oui = [0x18, 0xfe, 0x34];
|
|
265
|
-
} else if (((mac1 >> 16) & 0xff) == 1) {
|
|
266
|
-
oui = [0xac, 0xd0, 0x74];
|
|
267
|
-
} else {
|
|
268
|
-
throw "Couldnt determine OUI";
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
macAddr[0] = oui[0];
|
|
272
|
-
macAddr[1] = oui[1];
|
|
273
|
-
macAddr[2] = oui[2];
|
|
274
|
-
macAddr[3] = (mac1 >> 8) & 0xff;
|
|
275
|
-
macAddr[4] = mac1 & 0xff;
|
|
276
|
-
macAddr[5] = (mac0 >> 24) & 0xff;
|
|
277
|
-
} else if (this._chipfamily == ESP32) {
|
|
278
|
-
macAddr[0] = (mac2 >> 8) & 0xff;
|
|
279
|
-
macAddr[1] = mac2 & 0xff;
|
|
280
|
-
macAddr[2] = (mac1 >> 24) & 0xff;
|
|
281
|
-
macAddr[3] = (mac1 >> 16) & 0xff;
|
|
282
|
-
macAddr[4] = (mac1 >> 8) & 0xff;
|
|
283
|
-
macAddr[5] = mac1 & 0xff;
|
|
284
|
-
} else if ([ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily)) {
|
|
285
|
-
macAddr[0] = (mac1 >> 8) & 0xff;
|
|
286
|
-
macAddr[1] = mac1 & 0xff;
|
|
287
|
-
macAddr[2] = (mac0 >> 24) & 0xff;
|
|
288
|
-
macAddr[3] = (mac0 >> 16) & 0xff;
|
|
289
|
-
macAddr[4] = (mac0 >> 8) & 0xff;
|
|
290
|
-
macAddr[5] = mac0 & 0xff;
|
|
291
|
-
} else {
|
|
292
|
-
throw "Unknown chip family";
|
|
293
|
-
}
|
|
294
|
-
return macAddr;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
debugMsg(debugLevel, ...values) {
|
|
298
|
-
if (this.debug) {
|
|
299
|
-
this._debugMsg(debugLevel, ...values);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* @name _readEfuses
|
|
305
|
-
* Read the OTP data for this chip and store into this.efuses array
|
|
306
|
-
*/
|
|
307
|
-
async _readEfuses() {
|
|
308
|
-
let chipType = await this.chipType();
|
|
309
|
-
let chipInfo = this.getChipInfo(chipType);
|
|
310
|
-
for (let i = 0; i < 4; i++) {
|
|
311
|
-
this._efuses[i] = await this.readRegister(chipInfo.macFuseAddr + 4 * i);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* @name readRegister
|
|
317
|
-
* Read a register within the ESP chip RAM, returns a 4-element list
|
|
318
|
-
*/
|
|
319
|
-
async readRegister(reg) {
|
|
320
|
-
if (this.debug) {
|
|
321
|
-
this.debugMsg(1, "Reading from Register " + this.toHex(reg, 8));
|
|
322
|
-
}
|
|
323
|
-
let packet = struct.pack("<I", reg);
|
|
324
|
-
await this.command(ESP_READ_REG, packet);
|
|
325
|
-
let [val, data] = await this.getResponse(ESP_READ_REG);
|
|
326
|
-
return val;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
* @name writeRegister
|
|
331
|
-
* Write to a register within the ESP chip RAM, returns a 4-element list
|
|
332
|
-
*/
|
|
333
|
-
async writeRegister(
|
|
334
|
-
addr,
|
|
335
|
-
value,
|
|
336
|
-
mask = 0xffffffff,
|
|
337
|
-
delayUs = 0,
|
|
338
|
-
delayAfterUs = 0
|
|
339
|
-
) {
|
|
340
|
-
if (this.debug) {
|
|
341
|
-
this.debugMsg(1, "Writing to Register " + this.toHex(addr, 8));
|
|
342
|
-
}
|
|
343
|
-
let packet = struct.pack("<IIII", addr, value, mask, delayUs);
|
|
344
|
-
if (delayAfterUs > 0) {
|
|
345
|
-
packet = packet.concat(
|
|
346
|
-
struct.pack("<IIII", UART_DATE_REG_ADDR, 0, 0, delayAfterUs)
|
|
347
|
-
);
|
|
348
|
-
}
|
|
349
|
-
let returnVal = await this.checkCommand(ESP_WRITE_REG, packet);
|
|
350
|
-
return returnVal;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
sleep(ms) {
|
|
354
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* @name chipType
|
|
359
|
-
* ESP32 or ESP8266 based on which chip type we're talking to
|
|
360
|
-
*/
|
|
361
|
-
async chipType() {
|
|
362
|
-
if (this._chipfamily === null) {
|
|
363
|
-
this._chipfamily = await this.detectChip();
|
|
364
|
-
}
|
|
365
|
-
return this._chipfamily;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
getChipInfo(chipId) {
|
|
369
|
-
// Loop through supported chips and return the data for that chip
|
|
370
|
-
for (const [key, value] of Object.entries(supportedChips)) {
|
|
371
|
-
if (value["chipId"] == chipId) {
|
|
372
|
-
return value;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
throw "Chip Id is not Supported";
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
async detectChip() {
|
|
380
|
-
let chipMagicValue = await this.readRegister(CHIP_DETECT_MAGIC_REG_ADDR);
|
|
381
|
-
|
|
382
|
-
// Loop through magicValues and if the value matches, then the key is the chip ID
|
|
383
|
-
for (const [key, value] of Object.entries(supportedChips)) {
|
|
384
|
-
if (value["magicVal"].includes(chipMagicValue)) {
|
|
385
|
-
return value["chipId"];
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
throw "Unable to detect Chip";
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* @name chipType
|
|
393
|
-
* The specific name of the chip, e.g. ESP8266EX, to the best
|
|
394
|
-
* of our ability to determine without a stub bootloader.
|
|
395
|
-
*/
|
|
396
|
-
async chipName() {
|
|
397
|
-
let chipType = await this.chipType();
|
|
398
|
-
let chipInfo = this.getChipInfo(chipType);
|
|
399
|
-
await this._readEfuses();
|
|
400
|
-
if (chipType == ESP8266) {
|
|
401
|
-
if (this._efuses[0] & (1 << 4) || this._efuses[2] & (1 << 16)) {
|
|
402
|
-
return "ESP8285";
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
return chipInfo.chipName;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
* @name checkCommand
|
|
410
|
-
* Send a command packet, check that the command succeeded and
|
|
411
|
-
* return a tuple with the value and data.
|
|
412
|
-
* See the ESP Serial Protocol for more details on what value/data are
|
|
413
|
-
*/
|
|
414
|
-
async checkCommand(opcode, buffer, checksum = 0, timeout = DEFAULT_TIMEOUT) {
|
|
415
|
-
timeout = Math.min(timeout, MAX_TIMEOUT);
|
|
416
|
-
await this.command(opcode, buffer, checksum);
|
|
417
|
-
let [value, data] = await this.getResponse(opcode, timeout);
|
|
418
|
-
let statusLen;
|
|
419
|
-
if (data !== null) {
|
|
420
|
-
if (this.IS_STUB) {
|
|
421
|
-
statusLen = 2;
|
|
422
|
-
} else if (this._chipfamily == ESP8266) {
|
|
423
|
-
statusLen = 2;
|
|
424
|
-
} else if (
|
|
425
|
-
[ESP32, ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily)
|
|
426
|
-
) {
|
|
427
|
-
statusLen = 4;
|
|
428
|
-
} else {
|
|
429
|
-
if ([2, 4].includes(data.length)) {
|
|
430
|
-
statusLen = data.length;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
if (data === null || data.length < statusLen) {
|
|
436
|
-
throw "Didn't get enough status bytes";
|
|
437
|
-
}
|
|
438
|
-
let status = data.slice(-statusLen, data.length);
|
|
439
|
-
data = data.slice(0, -statusLen);
|
|
440
|
-
if (this.debug) {
|
|
441
|
-
this.debugMsg(1, "status", status);
|
|
442
|
-
this.debugMsg(1, "value", value);
|
|
443
|
-
this.debugMsg(1, "data", data);
|
|
444
|
-
}
|
|
445
|
-
if (status[0] == 1) {
|
|
446
|
-
if (status[1] == ROM_INVALID_RECV_MSG) {
|
|
447
|
-
throw "Invalid (unsupported) command " + this.toHex(opcode);
|
|
448
|
-
} else {
|
|
449
|
-
throw "Command failure error code " + this.toHex(status[1]);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
if (data.length > 0) {
|
|
454
|
-
return data;
|
|
455
|
-
}
|
|
456
|
-
return value;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
* @name timeoutPerMb
|
|
461
|
-
* Scales timeouts which are size-specific
|
|
462
|
-
*/
|
|
463
|
-
timeoutPerMb(secondsPerMb, sizeBytes) {
|
|
464
|
-
let result = Math.floor(secondsPerMb * (sizeBytes / 0x1e6));
|
|
465
|
-
if (result < DEFAULT_TIMEOUT) {
|
|
466
|
-
return DEFAULT_TIMEOUT;
|
|
467
|
-
}
|
|
468
|
-
return result;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
/**
|
|
472
|
-
* @name command
|
|
473
|
-
* Send a slip-encoded, checksummed command over the UART,
|
|
474
|
-
* does not check response
|
|
475
|
-
*/
|
|
476
|
-
async command(opcode, buffer, checksum = 0) {
|
|
477
|
-
//inputBuffer = []; // Reset input buffer
|
|
478
|
-
let packet = struct.pack("<BBHI", 0x00, opcode, buffer.length, checksum);
|
|
479
|
-
packet = packet.concat(buffer);
|
|
480
|
-
packet = this.slipEncode(packet);
|
|
481
|
-
this.debugMsg(
|
|
482
|
-
2,
|
|
483
|
-
"Writing " +
|
|
484
|
-
packet.length +
|
|
485
|
-
" byte" +
|
|
486
|
-
(packet.length == 1 ? "" : "s") +
|
|
487
|
-
":",
|
|
488
|
-
packet
|
|
489
|
-
);
|
|
490
|
-
await this.writeToStream(packet);
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
/**
|
|
494
|
-
* @name connect
|
|
495
|
-
* Opens a Web Serial connection to a micro:bit and sets up the input and
|
|
496
|
-
* output stream.
|
|
497
|
-
*/
|
|
498
|
-
async connect() {
|
|
499
|
-
// - Request a port and open a connection.
|
|
500
|
-
port = await navigator.serial.requestPort();
|
|
501
|
-
|
|
502
|
-
// - Wait for the port to open.toggleUIConnected
|
|
503
|
-
try {
|
|
504
|
-
// support chrome < 86
|
|
505
|
-
await port.open({ baudrate: ESP_ROM_BAUD, baudRate: ESP_ROM_BAUD });
|
|
506
|
-
} catch (e) {
|
|
507
|
-
port = null;
|
|
508
|
-
throw e;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
const signals = await port.getSignals();
|
|
512
|
-
|
|
513
|
-
this.logMsg("Connected successfully.");
|
|
514
|
-
|
|
515
|
-
this.logMsg("Try to reset.");
|
|
516
|
-
await port.setSignals({ dataTerminalReady: false, requestToSend: true });
|
|
517
|
-
await port.setSignals({ dataTerminalReady: true, requestToSend: false });
|
|
518
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
519
|
-
|
|
520
|
-
outputStream = port.writable;
|
|
521
|
-
inputStream = port.readable;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
connected() {
|
|
525
|
-
return !!port;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
/**
|
|
529
|
-
* @name disconnect
|
|
530
|
-
* Closes the Web Serial connection.
|
|
531
|
-
*/
|
|
532
|
-
async disconnect() {
|
|
533
|
-
if (reader) {
|
|
534
|
-
await reader.cancel();
|
|
535
|
-
reader = null;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
if (outputStream) {
|
|
539
|
-
await outputStream.getWriter().close();
|
|
540
|
-
outputStream = null;
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
await port.close();
|
|
544
|
-
port = null;
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
/**
|
|
548
|
-
* @name writeToStream
|
|
549
|
-
* Gets a writer from the output stream and send the raw data over WebSerial.
|
|
550
|
-
*/
|
|
551
|
-
async writeToStream(data) {
|
|
552
|
-
const writer = outputStream.getWriter();
|
|
553
|
-
await writer.write(new Uint8Array(data));
|
|
554
|
-
writer.releaseLock();
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
hexFormatter(bytes) {
|
|
558
|
-
return "[" + bytes.map((value) => this.toHex(value)).join(", ") + "]";
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
/**
|
|
562
|
-
* @name readPacket
|
|
563
|
-
* Generator to read SLIP packets from a serial port.
|
|
564
|
-
* Yields one full SLIP packet at a time, raises exception on timeout or invalid data.
|
|
565
|
-
* Designed to avoid too many calls to serial.read(1), which can bog
|
|
566
|
-
* down on slow systems.
|
|
567
|
-
*/
|
|
568
|
-
|
|
569
|
-
async readPacket() {
|
|
570
|
-
let partialPacket = null;
|
|
571
|
-
let inEscape = false;
|
|
572
|
-
let readBytes = [];
|
|
573
|
-
this.debugMsg(2, "Read Timeout", this.readTimeout);
|
|
574
|
-
while (true) {
|
|
575
|
-
let stamp = Date.now();
|
|
576
|
-
readBytes = [];
|
|
577
|
-
while (Date.now() - stamp < this.readTimeout) {
|
|
578
|
-
if (inputBuffer.length > 0) {
|
|
579
|
-
readBytes.push(inputBuffer.shift());
|
|
580
|
-
break;
|
|
581
|
-
} else {
|
|
582
|
-
await this.sleep(10);
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
if (readBytes.length == 0) {
|
|
586
|
-
let waitingFor = partialPacket === null ? "header" : "content";
|
|
587
|
-
this.debugMsg(1, "Timed out waiting for packet " + waitingFor);
|
|
588
|
-
console.error("Timed out waiting for packet " + waitingFor);
|
|
589
|
-
throw new SlipReadError("Timed out waiting for packet " + waitingFor);
|
|
590
|
-
}
|
|
591
|
-
this.debugMsg(
|
|
592
|
-
2,
|
|
593
|
-
"Read " + readBytes.length + " bytes: " + this.hexFormatter(readBytes)
|
|
594
|
-
);
|
|
595
|
-
for (let b of readBytes) {
|
|
596
|
-
if (partialPacket === null) {
|
|
597
|
-
// waiting for packet header
|
|
598
|
-
if (b == 0xc0) {
|
|
599
|
-
partialPacket = [];
|
|
600
|
-
} else {
|
|
601
|
-
this.debugMsg(
|
|
602
|
-
1,
|
|
603
|
-
"Read invalid data: " + this.hexFormatter(readBytes)
|
|
604
|
-
);
|
|
605
|
-
this.debugMsg(
|
|
606
|
-
1,
|
|
607
|
-
"Remaining data in serial buffer: " +
|
|
608
|
-
this.hexFormatter(inputBuffer)
|
|
609
|
-
);
|
|
610
|
-
throw new SlipReadError(
|
|
611
|
-
"Invalid head of packet (" + this.toHex(b) + ")"
|
|
612
|
-
);
|
|
613
|
-
}
|
|
614
|
-
} else if (inEscape) {
|
|
615
|
-
// part-way through escape sequence
|
|
616
|
-
inEscape = false;
|
|
617
|
-
if (b == 0xdc) {
|
|
618
|
-
partialPacket.push(0xc0);
|
|
619
|
-
} else if (b == 0xdd) {
|
|
620
|
-
partialPacket.push(0xdb);
|
|
621
|
-
} else {
|
|
622
|
-
this.debugMsg(
|
|
623
|
-
1,
|
|
624
|
-
"Read invalid data: " + this.hexFormatter(readBytes)
|
|
625
|
-
);
|
|
626
|
-
this.debugMsg(
|
|
627
|
-
1,
|
|
628
|
-
"Remaining data in serial buffer: " +
|
|
629
|
-
this.hexFormatter(inputBuffer)
|
|
630
|
-
);
|
|
631
|
-
throw new SlipReadError(
|
|
632
|
-
"Invalid SLIP escape (0xdb, " + this.toHex(b) + ")"
|
|
633
|
-
);
|
|
634
|
-
}
|
|
635
|
-
} else if (b == 0xdb) {
|
|
636
|
-
// start of escape sequence
|
|
637
|
-
inEscape = true;
|
|
638
|
-
} else if (b == 0xc0) {
|
|
639
|
-
// end of packet
|
|
640
|
-
this.debugMsg(
|
|
641
|
-
2,
|
|
642
|
-
"Received full packet: " + this.hexFormatter(partialPacket)
|
|
643
|
-
);
|
|
644
|
-
return partialPacket;
|
|
645
|
-
partialPacket = null;
|
|
646
|
-
} else {
|
|
647
|
-
// normal byte in packet
|
|
648
|
-
partialPacket.push(b);
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
return "";
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
/**
|
|
656
|
-
* @name getResponse
|
|
657
|
-
* Read response data and decodes the slip packet, then parses
|
|
658
|
-
* out the value/data and returns as a tuple of (value, data) where
|
|
659
|
-
* each is a list of bytes
|
|
660
|
-
*/
|
|
661
|
-
async getResponse(opcode, timeout = DEFAULT_TIMEOUT) {
|
|
662
|
-
this.readTimeout = timeout;
|
|
663
|
-
let packet;
|
|
664
|
-
let packetLength = 0;
|
|
665
|
-
let resp, opRet, lenRet, val, data;
|
|
666
|
-
for (let i = 0; i < 100; i++) {
|
|
667
|
-
try {
|
|
668
|
-
packet = await this.readPacket();
|
|
669
|
-
} catch (e) {
|
|
670
|
-
this.debugMsg(
|
|
671
|
-
1,
|
|
672
|
-
"Timed out after " + this.readTimeout + " milliseconds"
|
|
673
|
-
);
|
|
674
|
-
return [null, null];
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
if (packet.length < 8) {
|
|
678
|
-
continue;
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
[resp, opRet, lenRet, val] = struct.unpack("<BBHI", packet.slice(0, 8));
|
|
682
|
-
if (resp != 1) {
|
|
683
|
-
continue;
|
|
684
|
-
}
|
|
685
|
-
data = packet.slice(8);
|
|
686
|
-
if (opcode == null || opRet == opcode) {
|
|
687
|
-
return [val, data];
|
|
688
|
-
}
|
|
689
|
-
if (data[0] != 0 && data[1] == ROM_INVALID_RECV_MSG) {
|
|
690
|
-
inputBuffer = [];
|
|
691
|
-
throw "Invalid (unsupported) command " + this.toHex(opcode);
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
throw "Response doesn't match request";
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
/**
|
|
698
|
-
* @name read
|
|
699
|
-
* Read response data and decodes the slip packet.
|
|
700
|
-
* Keeps reading until we hit the timeout or get
|
|
701
|
-
* a packet closing byte
|
|
702
|
-
*/
|
|
703
|
-
async readBuffer(timeout = DEFAULT_TIMEOUT) {
|
|
704
|
-
this.readTimeout = timeout;
|
|
705
|
-
let packet;
|
|
706
|
-
try {
|
|
707
|
-
packet = await this.readPacket();
|
|
708
|
-
} catch (e) {
|
|
709
|
-
this.debugMsg(1, "Timed out after " + this.readTimeout + " milliseconds");
|
|
710
|
-
return null;
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
return packet;
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
/**
|
|
717
|
-
* @name checksum
|
|
718
|
-
* Calculate checksum of a blob, as it is defined by the ROM
|
|
719
|
-
*/
|
|
720
|
-
checksum(data, state = ESP_CHECKSUM_MAGIC) {
|
|
721
|
-
for (let b of data) {
|
|
722
|
-
state ^= b;
|
|
723
|
-
}
|
|
724
|
-
return state;
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
setPortBaudRate(baud) {
|
|
728
|
-
if (this.getChromeVersion() < 86) {
|
|
729
|
-
port.baudrate = baud;
|
|
730
|
-
} else {
|
|
731
|
-
port.baudRate = baud;
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
getPortBaudRate() {
|
|
736
|
-
if (this.getChromeVersion() < 86) {
|
|
737
|
-
return port.baudrate;
|
|
738
|
-
}
|
|
739
|
-
return port.baudRate;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
async setBaudrate(baud) {
|
|
743
|
-
if (this._chipfamily == ESP8266) {
|
|
744
|
-
this.logMsg("Baud rate can only change on ESP32 and ESP32-S2");
|
|
745
|
-
} else {
|
|
746
|
-
this.logMsg("Attempting to change baud rate to " + baud + "...");
|
|
747
|
-
try {
|
|
748
|
-
// stub takes the new baud rate and the old one
|
|
749
|
-
let oldBaud = this.IS_STUB ? this.getPortBaudRate() : 0;
|
|
750
|
-
let buffer = struct.pack("<II", baud, oldBaud);
|
|
751
|
-
await this.checkCommand(ESP_CHANGE_BAUDRATE, buffer);
|
|
752
|
-
this.setPortBaudRate(baud);
|
|
753
|
-
await this.sleep(50);
|
|
754
|
-
//inputBuffer = [];
|
|
755
|
-
this.logMsg("Changed baud rate to " + baud);
|
|
756
|
-
} catch (e) {
|
|
757
|
-
throw (
|
|
758
|
-
"Unable to change the baud rate, please try setting the connection speed from " +
|
|
759
|
-
baud +
|
|
760
|
-
" to 115200 and reconnecting."
|
|
761
|
-
);
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
/**
|
|
767
|
-
* @name sync
|
|
768
|
-
* Put into ROM bootload mode & attempt to synchronize with the
|
|
769
|
-
* ESP ROM bootloader, we will retry a few times
|
|
770
|
-
*/
|
|
771
|
-
async sync() {
|
|
772
|
-
this.logMsg("Performing sync...");
|
|
773
|
-
for (let i = 0; i < 5; i++) {
|
|
774
|
-
inputBuffer = [];
|
|
775
|
-
let response = await this._sync();
|
|
776
|
-
if (response) {
|
|
777
|
-
await this.sleep(100);
|
|
778
|
-
this.logMsg("Successfully synced.");
|
|
779
|
-
return true;
|
|
780
|
-
}
|
|
781
|
-
await this.sleep(100);
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
throw "Couldn't sync to ESP. Try resetting.";
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
/**
|
|
788
|
-
* @name _sync
|
|
789
|
-
* Perform a soft-sync using AT sync packets, does not perform
|
|
790
|
-
* any hardware resetting
|
|
791
|
-
*/
|
|
792
|
-
async _sync() {
|
|
793
|
-
await this.command(ESP_SYNC, SYNC_PACKET);
|
|
794
|
-
let [val, data] = await this.getResponse(ESP_SYNC, SYNC_TIMEOUT);
|
|
795
|
-
this.syncStubDetected = val === 0 ? 1 : 0;
|
|
796
|
-
for (let i = 0; i < 8; i++) {
|
|
797
|
-
let [val, data] = await this.getResponse(ESP_SYNC, SYNC_TIMEOUT);
|
|
798
|
-
this.syncStubDetected &= val === 0 ? 1 : 0;
|
|
799
|
-
if (data === null) {
|
|
800
|
-
continue;
|
|
801
|
-
}
|
|
802
|
-
if (data.length > 1 && data[0] == 0 && data[1] == 0) {
|
|
803
|
-
return true;
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
return false;
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
/**
|
|
810
|
-
* @name getFlashWriteSize
|
|
811
|
-
* Get the Flash write size based on the chip
|
|
812
|
-
*/
|
|
813
|
-
getFlashWriteSize() {
|
|
814
|
-
return FLASH_WRITE_SIZE;
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
/**
|
|
818
|
-
* @name flashData
|
|
819
|
-
* Program a full, uncompressed binary file into SPI Flash at
|
|
820
|
-
* a given offset. If an ESP32 and md5 string is passed in, will also
|
|
821
|
-
* verify memory. ESP8266 does not have checksum memory verification in
|
|
822
|
-
* ROM
|
|
823
|
-
*/
|
|
824
|
-
async flashData(binaryData, offset = 0, part = 0) {
|
|
825
|
-
let filesize = binaryData.byteLength;
|
|
826
|
-
this.logMsg("\nWriting data with filesize: " + filesize);
|
|
827
|
-
let blocks = await this.flashBegin(filesize, offset);
|
|
828
|
-
let block = [];
|
|
829
|
-
let seq = 0;
|
|
830
|
-
let written = 0;
|
|
831
|
-
let address = offset;
|
|
832
|
-
let position = 0;
|
|
833
|
-
let stamp = Date.now();
|
|
834
|
-
let flashWriteSize = this.getFlashWriteSize();
|
|
835
|
-
|
|
836
|
-
while (filesize - position > 0) {
|
|
837
|
-
let percentage = Math.floor((100 * (seq + 1)) / blocks);
|
|
838
|
-
/*this.logMsg(
|
|
839
|
-
"Writing at " + this.toHex(address + seq * flashWriteSize, 8) + "... (" + percentage + " %)"
|
|
840
|
-
);*/
|
|
841
|
-
if (this.updateProgress !== null) {
|
|
842
|
-
this.updateProgress(part, percentage);
|
|
843
|
-
}
|
|
844
|
-
if (filesize - position >= flashWriteSize) {
|
|
845
|
-
block = Array.from(
|
|
846
|
-
new Uint8Array(binaryData, position, flashWriteSize)
|
|
847
|
-
);
|
|
848
|
-
} else {
|
|
849
|
-
// Pad the last block
|
|
850
|
-
block = Array.from(
|
|
851
|
-
new Uint8Array(binaryData, position, filesize - position)
|
|
852
|
-
);
|
|
853
|
-
block = block.concat(
|
|
854
|
-
new Array(flashWriteSize - block.length).fill(0xff)
|
|
855
|
-
);
|
|
856
|
-
}
|
|
857
|
-
await this.flashBlock(block, seq);
|
|
858
|
-
seq += 1;
|
|
859
|
-
written += block.length;
|
|
860
|
-
position += flashWriteSize;
|
|
861
|
-
}
|
|
862
|
-
this.logMsg(
|
|
863
|
-
"Took " + (Date.now() - stamp) + "ms to write " + filesize + " bytes"
|
|
864
|
-
);
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
/**
|
|
868
|
-
* @name flashDeflBegin
|
|
869
|
-
* Start downloading compressed data to Flash (performs an erase)
|
|
870
|
-
* Returns number of blocks (size FLASH_WRITE_SIZE) to write.
|
|
871
|
-
*/
|
|
872
|
-
async flashDeflBegin(size, compsize, offset) {
|
|
873
|
-
let params;
|
|
874
|
-
let flashWriteSize = this.getFlashWriteSize();
|
|
875
|
-
let numBlocks = Math.floor(
|
|
876
|
-
(compsize + flashWriteSize - 1) / flashWriteSize
|
|
877
|
-
);
|
|
878
|
-
let eraseBlocks = Math.floor((size + flashWriteSize - 1) / flashWriteSize);
|
|
879
|
-
|
|
880
|
-
let stamp = Date.now();
|
|
881
|
-
let writeSize, timeout;
|
|
882
|
-
if (this.IS_STUB) {
|
|
883
|
-
writeSize = size; // stub expects number of bytes here, manages erasing internally
|
|
884
|
-
timeout = DEFAULT_TIMEOUT;
|
|
885
|
-
} else {
|
|
886
|
-
writeSize = eraseBlocks * self.FLASH_WRITE_SIZE; // ROM expects rounded up to erase block size
|
|
887
|
-
timeout = this.timeoutPerMb(ERASE_REGION_TIMEOUT_PER_MB, writeSize);
|
|
888
|
-
}
|
|
889
|
-
this.logMsg("Compressed " + size + " bytes to " + compsize + "...");
|
|
890
|
-
params = struct.pack("<IIII", writeSize, numBlocks, flashWriteSize, offset);
|
|
891
|
-
if (
|
|
892
|
-
[ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily) &&
|
|
893
|
-
!this.IS_STUB
|
|
894
|
-
) {
|
|
895
|
-
params = params.concat(struct.pack("<I", 0));
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
await this.checkCommand(ESP_FLASH_DEFL_BEGIN, params, 0, timeout);
|
|
899
|
-
|
|
900
|
-
if (size != 0 && !this.IS_STUB) {
|
|
901
|
-
// (stub erases as it writes, but ROM loaders erase on begin)
|
|
902
|
-
this.logMsg("Took " + (Date.now() - stamp) + "ms to erase flash block");
|
|
903
|
-
}
|
|
904
|
-
return numBlocks;
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
/**
|
|
908
|
-
* @name flashDeflBlock
|
|
909
|
-
* Write block to flash, send compressed
|
|
910
|
-
*/
|
|
911
|
-
async flashDeflBlock(data, seq, timeout = DEFAULT_TIMEOUT) {
|
|
912
|
-
await this.checkCommand(
|
|
913
|
-
ESP_FLASH_DEFL_DATA,
|
|
914
|
-
struct.pack("<IIII", data.length, seq, 0, 0).concat(data),
|
|
915
|
-
this.checksum(data),
|
|
916
|
-
timeout
|
|
917
|
-
);
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
/**
|
|
921
|
-
* @name flashDeflFinish
|
|
922
|
-
* Write block to flash, send compressed
|
|
923
|
-
*/
|
|
924
|
-
async flashDeflFinish(reboot = false) {
|
|
925
|
-
if (!reboot && !this.IS_STUB) {
|
|
926
|
-
// skip sending flash_finish to ROM loader, as this
|
|
927
|
-
// exits the bootloader. Stub doesn't do this.
|
|
928
|
-
return;
|
|
929
|
-
}
|
|
930
|
-
let pkt = struct.pack("<I", reboot ? 0 : 1);
|
|
931
|
-
await this.checkCommand(ESP_FLASH_DEFL_END, pkt);
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
/**
|
|
935
|
-
* @name flashBegin
|
|
936
|
-
* Prepare for flashing by attaching SPI chip and erasing the
|
|
937
|
-
* number of blocks requred.
|
|
938
|
-
*/
|
|
939
|
-
async flashBegin(size = 0, offset = 0, encrypted = false) {
|
|
940
|
-
let buffer;
|
|
941
|
-
let flashWriteSize = this.getFlashWriteSize();
|
|
942
|
-
if (!this.IS_STUB) {
|
|
943
|
-
if ([ESP32, ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily)) {
|
|
944
|
-
await this.checkCommand(ESP_SPI_ATTACH, new Array(8).fill(0));
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
//let flashId = await this.flashId();
|
|
948
|
-
|
|
949
|
-
if (this._chipfamily == ESP32) {
|
|
950
|
-
// We are hardcoded for 4MB flash on ESP32
|
|
951
|
-
buffer = struct.pack(
|
|
952
|
-
"<IIIIII",
|
|
953
|
-
0,
|
|
954
|
-
this._flashsize,
|
|
955
|
-
0x10000,
|
|
956
|
-
4096,
|
|
957
|
-
256,
|
|
958
|
-
0xffff
|
|
959
|
-
);
|
|
960
|
-
await this.checkCommand(ESP_SPI_SET_PARAMS, buffer);
|
|
961
|
-
}
|
|
962
|
-
let numBlocks = Math.floor((size + flashWriteSize - 1) / flashWriteSize);
|
|
963
|
-
let eraseSize = this.getEraseSize(offset, size);
|
|
964
|
-
|
|
965
|
-
let timeout;
|
|
966
|
-
if (this.IS_STUB) {
|
|
967
|
-
timeout = DEFAULT_TIMEOUT;
|
|
968
|
-
} else {
|
|
969
|
-
timeout = this.timeoutPerMb(ERASE_REGION_TIMEOUT_PER_MB, size);
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
let stamp = Date.now();
|
|
973
|
-
buffer = struct.pack("<IIII", eraseSize, numBlocks, flashWriteSize, offset);
|
|
974
|
-
if (
|
|
975
|
-
[ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily) &&
|
|
976
|
-
!this.IS_STUB
|
|
977
|
-
) {
|
|
978
|
-
buffer = buffer.concat(struct.pack("<I", encrypted ? 1 : 0));
|
|
979
|
-
}
|
|
980
|
-
this.logMsg(
|
|
981
|
-
"Erase size " +
|
|
982
|
-
eraseSize +
|
|
983
|
-
", blocks " +
|
|
984
|
-
numBlocks +
|
|
985
|
-
", block size " +
|
|
986
|
-
flashWriteSize +
|
|
987
|
-
", offset " +
|
|
988
|
-
this.toHex(offset, 4) +
|
|
989
|
-
", encrypted " +
|
|
990
|
-
(encrypted ? "yes" : "no")
|
|
991
|
-
);
|
|
992
|
-
await this.checkCommand(ESP_FLASH_BEGIN, buffer, 0, timeout);
|
|
993
|
-
if (size != 0 && !this.IS_STUB) {
|
|
994
|
-
this.logMsg(
|
|
995
|
-
"Took " + (Date.now() - stamp) + "ms to erase " + numBlocks + " bytes"
|
|
996
|
-
);
|
|
997
|
-
}
|
|
998
|
-
return numBlocks;
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
/**
|
|
1002
|
-
* @name flashBlock
|
|
1003
|
-
* Send one block of data to program into SPI Flash memory
|
|
1004
|
-
*/
|
|
1005
|
-
async flashBlock(data, seq, timeout = DEFAULT_TIMEOUT) {
|
|
1006
|
-
await this.checkCommand(
|
|
1007
|
-
ESP_FLASH_DATA,
|
|
1008
|
-
struct.pack("<IIII", data.length, seq, 0, 0).concat(data),
|
|
1009
|
-
this.checksum(data),
|
|
1010
|
-
timeout
|
|
1011
|
-
);
|
|
1012
|
-
}
|
|
1013
|
-
|
|
1014
|
-
async flashFinish() {
|
|
1015
|
-
let buffer = struct.pack("<I", 1);
|
|
1016
|
-
await this.checkCommand(ESP_FLASH_END, buffer);
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
/**
|
|
1020
|
-
* @name runSpiflashCommand
|
|
1021
|
-
* Run an arbitrary SPI flash command.
|
|
1022
|
-
* This function uses the "USR_COMMAND" functionality in the ESP
|
|
1023
|
-
* SPI hardware, rather than the precanned commands supported by
|
|
1024
|
-
* hardware. So the value of spiflash_command is an actual command
|
|
1025
|
-
* byte, sent over the wire.
|
|
1026
|
-
* After writing command byte, writes 'data' to MOSI and then
|
|
1027
|
-
* reads back 'read_bits' of reply on MISO. Result is a number.
|
|
1028
|
-
*/
|
|
1029
|
-
async runSpiflashCommand(
|
|
1030
|
-
spiflashCommand,
|
|
1031
|
-
data = [],
|
|
1032
|
-
readBits = 0,
|
|
1033
|
-
addr = null,
|
|
1034
|
-
addrLen = 0,
|
|
1035
|
-
dummyLen = 0
|
|
1036
|
-
) {
|
|
1037
|
-
let chipType = await this.chipType();
|
|
1038
|
-
let chipInfo = this.getChipInfo(chipType);
|
|
1039
|
-
|
|
1040
|
-
// SPI_USR register flags
|
|
1041
|
-
const SPI_USR_COMMAND = 1 << 31;
|
|
1042
|
-
const SPI_USR_ADDR = 1 << 30;
|
|
1043
|
-
const SPI_USR_DUMMY = 1 << 29;
|
|
1044
|
-
const SPI_USR_MISO = 1 << 28;
|
|
1045
|
-
const SPI_USR_MOSI = 1 << 27;
|
|
1046
|
-
|
|
1047
|
-
// SPI registers, base address differs ESP32* vs 8266
|
|
1048
|
-
const base = chipInfo.spiRegBase;
|
|
1049
|
-
const SPI_CMD_REG = base + 0x00;
|
|
1050
|
-
const SPI_ADDR_REG = base + 0x04;
|
|
1051
|
-
const SPI_USR_REG = base + chipInfo.spiUsrOffs;
|
|
1052
|
-
const SPI_USR1_REG = base + chipInfo.spiUsr1Offs;
|
|
1053
|
-
const SPI_USR2_REG = base + chipInfo.spiUsr2Offs;
|
|
1054
|
-
const SPI_W0_REG = base + chipInfo.spiW0Offs;
|
|
1055
|
-
|
|
1056
|
-
// shift values
|
|
1057
|
-
const SPI_USR2_COMMAND_LEN_SHIFT = 28;
|
|
1058
|
-
const SPI_USR_ADDR_LEN_SHIFT = 26;
|
|
1059
|
-
|
|
1060
|
-
// SPI peripheral "command" bitmasks for SPI_CMD_REG
|
|
1061
|
-
const SPI_CMD_USR = 1 << 18;
|
|
1062
|
-
|
|
1063
|
-
let setDataLengths;
|
|
1064
|
-
let flags;
|
|
1065
|
-
//following two registers are ESP32 and later chips only
|
|
1066
|
-
if (chipInfo.spiMosiDlenOffs != null) {
|
|
1067
|
-
// ESP32 and later chips have a more sophisticated way to set up "user" commands
|
|
1068
|
-
setDataLengths = async function (mosi_bits, miso_bits) {
|
|
1069
|
-
const SPI_MOSI_DLEN_REG = base + chipInfo.spiMosiDlenOffs;
|
|
1070
|
-
const SPI_MISO_DLEN_REG = base + chipInfo.spiMisoDlenOffs;
|
|
1071
|
-
if (mosi_bits > 0) {
|
|
1072
|
-
await this.writeRegister(SPI_MOSI_DLEN_REG, mosi_bits - 1);
|
|
1073
|
-
}
|
|
1074
|
-
if (miso_bits > 0) {
|
|
1075
|
-
await this.writeRegister(SPI_MISO_DLEN_REG, miso_bits - 1);
|
|
1076
|
-
}
|
|
1077
|
-
flags = 0;
|
|
1078
|
-
if (dummyLen > 0) {
|
|
1079
|
-
flags |= dummyLen - 1;
|
|
1080
|
-
}
|
|
1081
|
-
if (addrLen > 0) {
|
|
1082
|
-
flags |= (addrLen - 1) << SPI_USR_ADDR_LEN_SHIFT;
|
|
1083
|
-
}
|
|
1084
|
-
if (flags) {
|
|
1085
|
-
await this.writeRegister(SPI_USR1_REG, flags);
|
|
1086
|
-
}
|
|
1087
|
-
};
|
|
1088
|
-
} else {
|
|
1089
|
-
setDataLengths = async function (mosi_bits, miso_bits) {
|
|
1090
|
-
const SPI_DATA_LEN_REG = SPI_USR1_REG;
|
|
1091
|
-
const SPI_MOSI_BITLEN_S = 17;
|
|
1092
|
-
const SPI_MISO_BITLEN_S = 8;
|
|
1093
|
-
let mosi_mask = mosi_bits == 0 ? 0 : mosi_bits - 1;
|
|
1094
|
-
let miso_mask = miso_bits == 0 ? 0 : miso_bits - 1;
|
|
1095
|
-
flags =
|
|
1096
|
-
(miso_mask << SPI_MISO_BITLEN_S) | (mosi_mask << SPI_MOSI_BITLEN_S);
|
|
1097
|
-
if (dummyLen > 0) {
|
|
1098
|
-
flags |= dummyLen - 1;
|
|
1099
|
-
}
|
|
1100
|
-
if (addrLen > 0) {
|
|
1101
|
-
flags |= (addrLen - 1) << SPI_USR_ADDR_LEN_SHIFT;
|
|
1102
|
-
}
|
|
1103
|
-
await this.writeRegister(SPI_DATA_LEN_REG, flags);
|
|
1104
|
-
};
|
|
1105
|
-
}
|
|
1106
|
-
setDataLengths = setDataLengths.bind(this);
|
|
1107
|
-
if (readBits > 32) {
|
|
1108
|
-
throw new FatalError(
|
|
1109
|
-
"Reading more than 32 bits back from a SPI flash operation is unsupported"
|
|
1110
|
-
);
|
|
1111
|
-
}
|
|
1112
|
-
if (data.length > 64) {
|
|
1113
|
-
throw new FatalError(
|
|
1114
|
-
"Writing more than 64 bytes of data with one SPI command is unsupported"
|
|
1115
|
-
);
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
let dataBits = data.length * 8;
|
|
1119
|
-
let old_spi_usr = await this.readRegister(SPI_USR_REG);
|
|
1120
|
-
let old_spi_usr2 = await this.readRegister(SPI_USR2_REG);
|
|
1121
|
-
flags = SPI_USR_COMMAND;
|
|
1122
|
-
if (readBits > 0) {
|
|
1123
|
-
flags |= SPI_USR_MISO;
|
|
1124
|
-
}
|
|
1125
|
-
if (dataBits > 0) {
|
|
1126
|
-
flags |= SPI_USR_MOSI;
|
|
1127
|
-
}
|
|
1128
|
-
if (addrLen > 0) {
|
|
1129
|
-
flags |= SPI_USR_ADDR;
|
|
1130
|
-
}
|
|
1131
|
-
if (dummyLen > 0) {
|
|
1132
|
-
flags |= SPI_USR_DUMMY;
|
|
1133
|
-
}
|
|
1134
|
-
await setDataLengths(dataBits, readBits);
|
|
1135
|
-
await this.writeRegister(SPI_USR_REG, flags);
|
|
1136
|
-
await this.writeRegister(
|
|
1137
|
-
SPI_USR2_REG,
|
|
1138
|
-
(7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflashCommand
|
|
1139
|
-
);
|
|
1140
|
-
if (addr != null && addrLen > 0) {
|
|
1141
|
-
await this.writeRegister(SPI_ADDR_REG, addr);
|
|
1142
|
-
}
|
|
1143
|
-
if (dataBits == 0) {
|
|
1144
|
-
await this.writeRegister(SPI_W0_REG, 0); // clear data register before we read it
|
|
1145
|
-
} else {
|
|
1146
|
-
data = data.concat(new Array(4 - data.length).fill(0)); // pad to 32-bit multiple
|
|
1147
|
-
let words = struct.unpack("I" * Math.floor(data.length / 4), data);
|
|
1148
|
-
let next_reg = SPI_W0_REG;
|
|
1149
|
-
for (let word of words) {
|
|
1150
|
-
await this.writeRegister(next_reg, word);
|
|
1151
|
-
next_reg += 4;
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
await this.writeRegister(SPI_CMD_REG, SPI_CMD_USR);
|
|
1155
|
-
|
|
1156
|
-
let waitDone = async function () {
|
|
1157
|
-
for (let i = 0; i < 10; i++) {
|
|
1158
|
-
if (((await this.readRegister(SPI_CMD_REG)) & SPI_CMD_USR) == 0) {
|
|
1159
|
-
return;
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
throw new FatalError("SPI command did not complete in time");
|
|
1163
|
-
};
|
|
1164
|
-
waitDone = waitDone.bind(this);
|
|
1165
|
-
await waitDone();
|
|
1166
|
-
|
|
1167
|
-
let status = await this.readRegister(SPI_W0_REG);
|
|
1168
|
-
// restore some SPI controller registers
|
|
1169
|
-
await this.writeRegister(SPI_USR_REG, old_spi_usr);
|
|
1170
|
-
await this.writeRegister(SPI_USR2_REG, old_spi_usr2);
|
|
1171
|
-
return status;
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
async flashId() {
|
|
1175
|
-
const SPIFLASH_RDID = 0x9f;
|
|
1176
|
-
|
|
1177
|
-
return await this.runSpiflashCommand(SPIFLASH_RDID, [], 24);
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
/**
|
|
1181
|
-
* @name getEraseSize
|
|
1182
|
-
* Calculate an erase size given a specific size in bytes.
|
|
1183
|
-
* Provides a workaround for the bootloader erase bug on ESP8266.
|
|
1184
|
-
*/
|
|
1185
|
-
getEraseSize(offset, size) {
|
|
1186
|
-
if (this._chipfamily != ESP8266 || this.IS_STUB) {
|
|
1187
|
-
return size;
|
|
1188
|
-
}
|
|
1189
|
-
let sectorsPerBlock = 16;
|
|
1190
|
-
let sectorSize = FLASH_SECTOR_SIZE;
|
|
1191
|
-
let numSectors = Math.floor((size + sectorSize - 1) / sectorSize);
|
|
1192
|
-
let startSector = Math.floor(offset / sectorSize);
|
|
1193
|
-
|
|
1194
|
-
let headSectors = sectorsPerBlock - (startSector % sectorsPerBlock);
|
|
1195
|
-
if (numSectors < headSectors) {
|
|
1196
|
-
headSectors = numSectors;
|
|
1197
|
-
}
|
|
1198
|
-
|
|
1199
|
-
if (numSectors < 2 * headSectors) {
|
|
1200
|
-
return Math.floor(((numSectors + 1) / 2) * sectorSize);
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
return (numSectors - headSectors) * sectorSize;
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
/**
|
|
1207
|
-
* @name memBegin (592)
|
|
1208
|
-
* Start downloading an application image to RAM
|
|
1209
|
-
*/
|
|
1210
|
-
async memBegin(size, blocks, blocksize, offset) {
|
|
1211
|
-
if (this.IS_STUB) {
|
|
1212
|
-
let stub = await this.getStubCode();
|
|
1213
|
-
let load_start = offset;
|
|
1214
|
-
let load_end = offset + size;
|
|
1215
|
-
for (let [start, end] of [
|
|
1216
|
-
[stub.data_start, stub.data_start + stub.data.length],
|
|
1217
|
-
[stub.text_start, stub.text_start + stub.text.length],
|
|
1218
|
-
]) {
|
|
1219
|
-
if (load_start < end && load_end > start) {
|
|
1220
|
-
throw (
|
|
1221
|
-
"Software loader is resident at " +
|
|
1222
|
-
this.toHex(start, 8) +
|
|
1223
|
-
"-" +
|
|
1224
|
-
this.toHex(end, 8) +
|
|
1225
|
-
". " +
|
|
1226
|
-
"Can't load binary at overlapping address range " +
|
|
1227
|
-
this.toHex(load_start, 8) +
|
|
1228
|
-
"-" +
|
|
1229
|
-
this.toHex(load_end, 8) +
|
|
1230
|
-
". " +
|
|
1231
|
-
"Try changing the binary loading address."
|
|
1232
|
-
);
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
return this.checkCommand(
|
|
1238
|
-
ESP_MEM_BEGIN,
|
|
1239
|
-
struct.pack("<IIII", size, blocks, blocksize, offset)
|
|
1240
|
-
);
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
/**
|
|
1244
|
-
* @name memBlock (609)
|
|
1245
|
-
* Send a block of an image to RAM
|
|
1246
|
-
*/
|
|
1247
|
-
async memBlock(data, seq) {
|
|
1248
|
-
return await this.checkCommand(
|
|
1249
|
-
ESP_MEM_DATA,
|
|
1250
|
-
struct.pack("<IIII", data.length, seq, 0, 0).concat(data),
|
|
1251
|
-
this.checksum(data)
|
|
1252
|
-
);
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
/**
|
|
1256
|
-
* @name memFinish (615)
|
|
1257
|
-
* Leave download mode and run the application
|
|
1258
|
-
*
|
|
1259
|
-
* Sending ESP_MEM_END usually sends a correct response back, however sometimes
|
|
1260
|
-
* (with ROM loader) the executed code may reset the UART or change the baud rate
|
|
1261
|
-
* before the transmit FIFO is empty. So in these cases we set a short timeout and
|
|
1262
|
-
* ignore errors.
|
|
1263
|
-
*/
|
|
1264
|
-
async memFinish(entrypoint = 0) {
|
|
1265
|
-
let timeout = this.IS_STUB ? DEFAULT_TIMEOUT : MEM_END_ROM_TIMEOUT;
|
|
1266
|
-
let data = struct.pack("<II", parseInt(entrypoint == 0), entrypoint);
|
|
1267
|
-
try {
|
|
1268
|
-
return await this.checkCommand(ESP_MEM_END, data, 0, timeout);
|
|
1269
|
-
} catch (e) {
|
|
1270
|
-
if (this.IS_STUB) {
|
|
1271
|
-
throw e;
|
|
1272
|
-
}
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
async getStubCode() {
|
|
1277
|
-
let chipType = await this.chipType();
|
|
1278
|
-
let chipInfo = this.getChipInfo(chipType);
|
|
1279
|
-
|
|
1280
|
-
let response = await fetch("stubs/" + chipInfo.stubFile + ".json");
|
|
1281
|
-
let stubcode = await response.json();
|
|
1282
|
-
|
|
1283
|
-
// Base64 decode the text and data
|
|
1284
|
-
stubcode.text = toByteArray(atob(stubcode.text));
|
|
1285
|
-
stubcode.data = toByteArray(atob(stubcode.data));
|
|
1286
|
-
return stubcode;
|
|
1287
|
-
}
|
|
1288
|
-
|
|
1289
|
-
getStubLoaderClass() {
|
|
1290
|
-
// Based on current chip, we return the appropriate stub loader class
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
|
-
getRomClass() {
|
|
1294
|
-
// Based on current chip, we return the appropriate Rom class
|
|
1295
|
-
}
|
|
1296
|
-
|
|
1297
|
-
async runStub(stub = null) {
|
|
1298
|
-
if (stub === null) {
|
|
1299
|
-
stub = await this.getStubCode();
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
|
-
if (this.syncStubDetected || this.IS_STUB) {
|
|
1303
|
-
this.logMsg("Stub is already running. No upload is necessary.");
|
|
1304
|
-
return this.stubClass;
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
let ramBlock = ESP_RAM_BLOCK;
|
|
1308
|
-
// We're transferring over USB, right?
|
|
1309
|
-
if ([ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily)) {
|
|
1310
|
-
ramBlock = USB_RAM_BLOCK;
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
// Upload
|
|
1314
|
-
this.logMsg("Uploading stub...");
|
|
1315
|
-
for (let field of ["text", "data"]) {
|
|
1316
|
-
if (Object.keys(stub).includes(field)) {
|
|
1317
|
-
let offset = stub[field + "_start"];
|
|
1318
|
-
let length = stub[field].length;
|
|
1319
|
-
let blocks = Math.floor((length + ramBlock - 1) / ramBlock);
|
|
1320
|
-
await this.memBegin(length, blocks, ramBlock, offset);
|
|
1321
|
-
for (let seq of Array(blocks).keys()) {
|
|
1322
|
-
let fromOffs = seq * ramBlock;
|
|
1323
|
-
let toOffs = fromOffs + ramBlock;
|
|
1324
|
-
if (toOffs > length) {
|
|
1325
|
-
toOffs = length;
|
|
1326
|
-
}
|
|
1327
|
-
await this.memBlock(stub[field].slice(fromOffs, toOffs), seq);
|
|
1328
|
-
}
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
this.logMsg("Running stub...");
|
|
1332
|
-
await this.memFinish(stub["entry"]);
|
|
1333
|
-
|
|
1334
|
-
let p = await this.readBuffer(500);
|
|
1335
|
-
p = String.fromCharCode(...p);
|
|
1336
|
-
|
|
1337
|
-
if (p != "OHAI") {
|
|
1338
|
-
throw "Failed to start stub. Unexpected response: " + p;
|
|
1339
|
-
}
|
|
1340
|
-
this.logMsg("Stub is now running...");
|
|
1341
|
-
let stubLoader = new EspStubLoader({
|
|
1342
|
-
updateProgress: this.updateProgress,
|
|
1343
|
-
logMsg: this.logMsg,
|
|
1344
|
-
debugMsg: this._debugMsg,
|
|
1345
|
-
debug: this.debug,
|
|
1346
|
-
});
|
|
1347
|
-
stubLoader.stubClass = stubLoader;
|
|
1348
|
-
return stubLoader;
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
|
|
1352
|
-
class EspStubLoader extends EspLoader {
|
|
1353
|
-
/*
|
|
1354
|
-
The Stubloader has commands that run on the uploaded Stub Code in RAM
|
|
1355
|
-
rather than built in commands.
|
|
1356
|
-
*/
|
|
1357
|
-
constructor(params) {
|
|
1358
|
-
super(params);
|
|
1359
|
-
this.IS_STUB = true;
|
|
1360
|
-
}
|
|
1361
|
-
/**
|
|
1362
|
-
* @name eraseFlash
|
|
1363
|
-
* depending on flash chip model the erase may take this long (maybe longer!)
|
|
1364
|
-
*/
|
|
1365
|
-
async eraseFlash() {
|
|
1366
|
-
await this.checkCommand(ESP_ERASE_FLASH, [], 0, CHIP_ERASE_TIMEOUT);
|
|
1367
|
-
}
|
|
1368
|
-
|
|
1369
|
-
/**
|
|
1370
|
-
* @name getFlashWriteSize
|
|
1371
|
-
* Get the Flash write size based on the chip
|
|
1372
|
-
*/
|
|
1373
|
-
getFlashWriteSize() {
|
|
1374
|
-
return STUBLOADER_FLASH_WRITE_SIZE;
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
|
|
1378
|
-
class Esp32StubLoader extends EspStubLoader {}
|
|
1379
|
-
|
|
1380
|
-
/*
|
|
1381
|
-
Represents error when NVS Partition size given is insufficient
|
|
1382
|
-
to accomodate the data in the given csv file
|
|
1383
|
-
*/
|
|
1384
|
-
class SlipReadError extends Error {
|
|
1385
|
-
constructor(message) {
|
|
1386
|
-
super(message);
|
|
1387
|
-
this.name = "SlipReadError";
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
1390
|
-
|
|
1391
|
-
class FatalError extends Error {
|
|
1392
|
-
constructor(message) {
|
|
1393
|
-
super(message);
|
|
1394
|
-
this.name = "FatalError";
|
|
1395
|
-
}
|
|
1396
|
-
}
|