tasmota-webserial-esptool 6.0.2 → 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.
Files changed (77) hide show
  1. package/.devcontainer/devcontainer.json +13 -13
  2. package/.github/workflows/build_upload.yml +6 -7
  3. package/.github/workflows/ci.yml +2 -1
  4. package/README.md +1 -5
  5. package/css/dark.css +6 -4
  6. package/css/light.css +5 -2
  7. package/dist/const.d.ts +35 -1
  8. package/dist/const.js +82 -1
  9. package/dist/esp_loader.js +17 -5
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/stubs/esp32.json +7 -1
  13. package/dist/stubs/esp32c2.json +7 -0
  14. package/dist/stubs/esp32c3.json +7 -1
  15. package/dist/stubs/esp32c6.json +7 -0
  16. package/dist/stubs/esp32h2.json +7 -0
  17. package/dist/stubs/esp32s2.json +7 -1
  18. package/dist/stubs/esp32s3.json +7 -1
  19. package/dist/stubs/esp8266.json +7 -1
  20. package/dist/stubs/index.js +10 -1
  21. package/dist/web/esp32-165a50ff.js +1 -0
  22. package/dist/web/esp32c2-895e50a1.js +1 -0
  23. package/dist/web/esp32c3-dc0915b5.js +1 -0
  24. package/dist/web/esp32c6-2dda1f55.js +1 -0
  25. package/dist/web/esp32h2-064ce7cf.js +1 -0
  26. package/dist/web/esp32s2-ffc43e14.js +1 -0
  27. package/dist/web/esp32s3-857df8a8.js +1 -0
  28. package/dist/web/esp8266-a8241797.js +1 -0
  29. package/dist/web/index.js +1 -1
  30. package/index.html +1 -1
  31. package/js/modules/esp32-165a50ff.js +1 -0
  32. package/js/modules/esp32c2-895e50a1.js +1 -0
  33. package/js/modules/esp32c3-dc0915b5.js +1 -0
  34. package/js/modules/esp32c6-2dda1f55.js +1 -0
  35. package/js/modules/esp32h2-064ce7cf.js +1 -0
  36. package/js/modules/esp32s2-ffc43e14.js +1 -0
  37. package/js/modules/esp32s3-857df8a8.js +1 -0
  38. package/js/modules/esp8266-a8241797.js +1 -0
  39. package/js/modules/esptool.js +1 -1
  40. package/js/script.js +3 -3
  41. package/js/utilities.js +132 -98
  42. package/license.md +0 -1
  43. package/package.json +9 -9
  44. package/rollup.config.js +1 -1
  45. package/script/build +4 -0
  46. package/src/const.ts +88 -3
  47. package/src/esp_loader.ts +68 -53
  48. package/src/index.ts +1 -0
  49. package/src/stubs/esp32.json +7 -1
  50. package/src/stubs/esp32c2.json +7 -1
  51. package/src/stubs/esp32c3.json +7 -1
  52. package/src/stubs/esp32c6.json +7 -0
  53. package/src/stubs/esp32h2.json +7 -1
  54. package/src/stubs/esp32s2.json +7 -1
  55. package/src/stubs/esp32s3.json +7 -1
  56. package/src/stubs/esp8266.json +7 -1
  57. package/src/stubs/index.ts +10 -1
  58. package/dist/web/esp32-a2dcbc2e.js +0 -1
  59. package/dist/web/esp32c3-18e9678b.js +0 -1
  60. package/dist/web/esp32s2-3109ccc6.js +0 -1
  61. package/dist/web/esp32s3-c1dbd867.js +0 -1
  62. package/dist/web/esp8266-144419c0.js +0 -1
  63. package/js/esptool.js +0 -1292
  64. package/js/modules/esp32-a2dcbc2e.js +0 -1
  65. package/js/modules/esp32c3-18e9678b.js +0 -1
  66. package/js/modules/esp32s2-3109ccc6.js +0 -1
  67. package/js/modules/esp32s3-c1dbd867.js +0 -1
  68. package/js/modules/esp8266-144419c0.js +0 -1
  69. package/script/stubgen.py +0 -47
  70. package/stubs/esp32.json +0 -7
  71. package/stubs/esp32c2.json +0 -1
  72. package/stubs/esp32c3.json +0 -7
  73. package/stubs/esp32c6.json +0 -7
  74. package/stubs/esp32h2.json +0 -1
  75. package/stubs/esp32s2.json +0 -7
  76. package/stubs/esp32s3.json +0 -7
  77. package/stubs/esp8266.json +0 -7
package/js/esptool.js DELETED
@@ -1,1292 +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("\x07\x07\x12 UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU");
52
- const CHIP_DETECT_MAGIC_REG_ADDR = 0x40001000;
53
- const ESP8266 = 0x8266;
54
- const ESP32 = 0x32;
55
- const ESP32S2 = 0x3252;
56
- const ESP32S3 = 0x3253;
57
- const ESP32C3 = 0x32C3;
58
-
59
- // Commands supported by ESP8266 ROM bootloader
60
- const ESP_FLASH_BEGIN = 0x02;
61
- const ESP_FLASH_DATA = 0x03;
62
- const ESP_FLASH_END = 0x04;
63
- const ESP_MEM_BEGIN = 0x05;
64
- const ESP_MEM_END = 0x06;
65
- const ESP_MEM_DATA = 0x07;
66
- const ESP_SYNC = 0x08;
67
- const ESP_WRITE_REG = 0x09;
68
- const ESP_READ_REG = 0x0A;
69
-
70
- // Some comands supported by ESP32 ROM bootloader (or -8266 w/ stub)
71
- const ESP_SPI_SET_PARAMS = 0x0B;
72
- const ESP_SPI_ATTACH = 0x0D;
73
- const ESP_READ_FLASH_SLOW = 0x0E // ROM only, much slower than the stub flash read
74
- const ESP_CHANGE_BAUDRATE = 0x0F;
75
- const ESP_FLASH_DEFL_BEGIN = 0x10
76
- const ESP_FLASH_DEFL_DATA = 0x11
77
- const ESP_FLASH_DEFL_END = 0x12
78
- const ESP_SPI_FLASH_MD5 = 0x13;
79
-
80
- // Commands supported by ESP32-S2/S3/C3/C6 ROM bootloader only
81
- const ESP_GET_SECURITY_INFO = 0x14;
82
-
83
- // Some commands supported by stub only
84
- const ESP_ERASE_FLASH = 0xD0;
85
- const ESP_ERASE_REGION = 0xD1;
86
- const ESP_READ_FLASH = 0xD2;
87
- const ESP_RUN_USER_CODE = 0xD3;
88
-
89
- // Response code(s) sent by ROM
90
- const ROM_INVALID_RECV_MSG = 0x05;
91
-
92
- // Initial state for the checksum routine
93
- const ESP_CHECKSUM_MAGIC = 0xEF;
94
-
95
-
96
- const UART_DATE_REG_ADDR = 0x60000078;
97
-
98
- const USB_RAM_BLOCK = 0x800;
99
- const ESP_RAM_BLOCK = 0x1800;
100
-
101
- // Timeouts
102
- const DEFAULT_TIMEOUT = 3000;
103
- const CHIP_ERASE_TIMEOUT = 120000; // timeout for full chip erase in ms
104
- const MAX_TIMEOUT = CHIP_ERASE_TIMEOUT * 2; // longest any command can run in ms
105
- const SYNC_TIMEOUT = 100; // timeout for syncing with bootloader in ms
106
- const ERASE_REGION_TIMEOUT_PER_MB = 30000; // timeout (per megabyte) for erasing a region in ms
107
- const MEM_END_ROM_TIMEOUT = 500;
108
-
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(addr, value, mask=0xFFFFFFFF, delayUs=0, delayAfterUs=0) {
334
- if (this.debug) {
335
- this.debugMsg(1, "Writing to Register " + this.toHex(addr, 8));
336
- }
337
- let packet = struct.pack("<IIII", addr, value, mask, delayUs);
338
- if (delayAfterUs > 0) {
339
- packet = packet.concat(struct.pack('<IIII', UART_DATE_REG_ADDR, 0, 0, delayAfterUs))
340
- }
341
- let returnVal = await this.checkCommand(ESP_WRITE_REG, packet);
342
- return returnVal;
343
- };
344
-
345
- sleep(ms) {
346
- return new Promise(resolve => setTimeout(resolve, ms));
347
- }
348
-
349
- /**
350
- * @name chipType
351
- * ESP32 or ESP8266 based on which chip type we're talking to
352
- */
353
- async chipType() {
354
- if (this._chipfamily === null) {
355
- this._chipfamily = await this.detectChip()
356
- }
357
- return this._chipfamily;
358
- };
359
-
360
- getChipInfo(chipId) {
361
- // Loop through supported chips and return the data for that chip
362
- for (const [key, value] of Object.entries(supportedChips)) {
363
- if (value["chipId"] == chipId) {
364
- return value;
365
- }
366
- }
367
-
368
- throw("Chip Id is not Supported")
369
- }
370
-
371
- async detectChip() {
372
- let chipMagicValue = await this.readRegister(CHIP_DETECT_MAGIC_REG_ADDR);
373
-
374
- // Loop through magicValues and if the value matches, then the key is the chip ID
375
- for (const [key, value] of Object.entries(supportedChips)) {
376
- if (value["magicVal"].includes(chipMagicValue)) {
377
- return value["chipId"]
378
- }
379
- }
380
- throw("Unable to detect Chip");
381
- }
382
-
383
- /**
384
- * @name chipType
385
- * The specific name of the chip, e.g. ESP8266EX, to the best
386
- * of our ability to determine without a stub bootloader.
387
- */
388
- async chipName() {
389
- let chipType = await this.chipType();
390
- let chipInfo = this.getChipInfo(chipType);
391
- await this._readEfuses();
392
- if (chipType == ESP8266) {
393
- if (this._efuses[0] & (1 << 4) || this._efuses[2] & (1 << 16)) {
394
- return "ESP8285";
395
- }
396
- }
397
- return chipInfo.chipName;
398
- };
399
-
400
- /**
401
- * @name checkCommand
402
- * Send a command packet, check that the command succeeded and
403
- * return a tuple with the value and data.
404
- * See the ESP Serial Protocol for more details on what value/data are
405
- */
406
- async checkCommand(opcode, buffer, checksum=0, timeout=DEFAULT_TIMEOUT) {
407
- timeout = Math.min(timeout, MAX_TIMEOUT);
408
- await this.command(opcode, buffer, checksum);
409
- let [value, data] = await this.getResponse(opcode, timeout);
410
- let statusLen;
411
- if (data !== null) {
412
- if (this.IS_STUB) {
413
- statusLen = 2;
414
- } else if (this._chipfamily == ESP8266) {
415
- statusLen = 2;
416
- } else if ([ESP32, ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily)) {
417
- statusLen = 4;
418
- } else {
419
- if ([2, 4].includes(data.length)) {
420
- statusLen = data.length;
421
- }
422
- }
423
- }
424
-
425
- if (data === null || data.length < statusLen) {
426
- throw("Didn't get enough status bytes");
427
- }
428
- let status = data.slice(-statusLen, data.length);
429
- data = data.slice(0, -statusLen);
430
- if (this.debug) {
431
- this.debugMsg(1, "status", status);
432
- this.debugMsg(1, "value", value);
433
- this.debugMsg(1, "data", data);
434
- }
435
- if (status[0] == 1) {
436
- if (status[1] == ROM_INVALID_RECV_MSG) {
437
- throw("Invalid (unsupported) command " + this.toHex(opcode));
438
- } else {
439
- throw("Command failure error code " + this.toHex(status[1]));
440
- }
441
- }
442
-
443
- if (data.length > 0) {
444
- return data;
445
- }
446
- return value;
447
- };
448
-
449
- /**
450
- * @name timeoutPerMb
451
- * Scales timeouts which are size-specific
452
- */
453
- timeoutPerMb(secondsPerMb, sizeBytes) {
454
- let result = Math.floor(secondsPerMb * (sizeBytes / 0x1e6));
455
- if (result < DEFAULT_TIMEOUT) {
456
- return DEFAULT_TIMEOUT;
457
- }
458
- return result;
459
- };
460
-
461
- /**
462
- * @name command
463
- * Send a slip-encoded, checksummed command over the UART,
464
- * does not check response
465
- */
466
- async command(opcode, buffer, checksum=0) {
467
- //inputBuffer = []; // Reset input buffer
468
- let packet = struct.pack("<BBHI", 0x00, opcode, buffer.length, checksum);
469
- packet = packet.concat(buffer);
470
- packet = this.slipEncode(packet);
471
- this.debugMsg(2, "Writing " + packet.length + " byte" + (packet.length == 1 ? "" : "s") + ":", packet);
472
- await this.writeToStream(packet);
473
- };
474
-
475
- /**
476
- * @name connect
477
- * Opens a Web Serial connection to a micro:bit and sets up the input and
478
- * output stream.
479
- */
480
- async connect() {
481
- // - Request a port and open a connection.
482
- port = await navigator.serial.requestPort();
483
-
484
- // - Wait for the port to open.toggleUIConnected
485
- try {
486
- // support chrome < 86
487
- await port.open({ baudrate: ESP_ROM_BAUD, baudRate: ESP_ROM_BAUD });
488
- } catch(e) {
489
- port = null;
490
- throw e;
491
- }
492
-
493
- const signals = await port.getSignals();
494
-
495
- this.logMsg("Connected successfully.")
496
-
497
- this.logMsg("Try to reset.")
498
- await port.setSignals({ dataTerminalReady: false, requestToSend: true });
499
- await port.setSignals({ dataTerminalReady: true, requestToSend: false });
500
- await new Promise(resolve => setTimeout(resolve, 1000));
501
-
502
- outputStream = port.writable;
503
- inputStream = port.readable;
504
- }
505
-
506
- connected() {
507
- return !!port;
508
- }
509
-
510
- /**
511
- * @name disconnect
512
- * Closes the Web Serial connection.
513
- */
514
- async disconnect() {
515
- if (reader) {
516
- await reader.cancel();
517
- reader = null;
518
- }
519
-
520
- if (outputStream) {
521
- await outputStream.getWriter().close();
522
- outputStream = null;
523
- }
524
-
525
- await port.close();
526
- port = null;
527
- }
528
-
529
- /**
530
- * @name writeToStream
531
- * Gets a writer from the output stream and send the raw data over WebSerial.
532
- */
533
- async writeToStream(data) {
534
- const writer = outputStream.getWriter();
535
- await writer.write(new Uint8Array(data));
536
- writer.releaseLock();
537
- }
538
-
539
- hexFormatter(bytes) {
540
- return "[" + bytes.map(value => this.toHex(value)).join(", ") + "]"
541
- }
542
-
543
- /**
544
- * @name readPacket
545
- * Generator to read SLIP packets from a serial port.
546
- * Yields one full SLIP packet at a time, raises exception on timeout or invalid data.
547
- * Designed to avoid too many calls to serial.read(1), which can bog
548
- * down on slow systems.
549
- */
550
-
551
- async readPacket() {
552
- let partialPacket = null;
553
- let inEscape = false;
554
- let readBytes = [];
555
- this.debugMsg(2, "Read Timeout", this.readTimeout)
556
- while (true) {
557
- let stamp = Date.now();
558
- readBytes = [];
559
- while (Date.now() - stamp < this.readTimeout) {
560
- if (inputBuffer.length > 0) {
561
- readBytes.push(inputBuffer.shift());
562
- break;
563
- } else {
564
- await this.sleep(10);
565
- }
566
- }
567
- if (readBytes.length == 0) {
568
- let waitingFor = partialPacket === null ? "header" : "content";
569
- this.debugMsg(1, "Timed out waiting for packet " + waitingFor);
570
- console.error("Timed out waiting for packet " + waitingFor)
571
- throw new SlipReadError("Timed out waiting for packet " + waitingFor);
572
- }
573
- this.debugMsg(2, "Read " + readBytes.length + " bytes: " + this.hexFormatter(readBytes));
574
- for (let b of readBytes) {
575
- if (partialPacket === null) { // waiting for packet header
576
- if (b == 0xc0) {
577
- partialPacket = [];
578
- } else {
579
- this.debugMsg(1, "Read invalid data: " + this.hexFormatter(readBytes));
580
- this.debugMsg(1, "Remaining data in serial buffer: " + this.hexFormatter(inputBuffer));
581
- throw new SlipReadError('Invalid head of packet (' + this.toHex(b) + ')');
582
- }
583
- } else if (inEscape) { // part-way through escape sequence
584
- inEscape = false;
585
- if (b == 0xdc) {
586
- partialPacket.push(0xc0);
587
- } else if (b == 0xdd) {
588
- partialPacket.push(0xdb);
589
- } else {
590
- this.debugMsg(1, "Read invalid data: " + this.hexFormatter(readBytes));
591
- this.debugMsg(1, "Remaining data in serial buffer: " + this.hexFormatter(inputBuffer));
592
- throw new SlipReadError('Invalid SLIP escape (0xdb, ' + this.toHex(b) + ')');
593
- }
594
- } else if (b == 0xdb) { // start of escape sequence
595
- inEscape = true;
596
- } else if (b == 0xc0) { // end of packet
597
- this.debugMsg(2, "Received full packet: " + this.hexFormatter(partialPacket))
598
- return partialPacket;
599
- partialPacket = null;
600
- } else { // normal byte in packet
601
- partialPacket.push(b);
602
- }
603
- }
604
- }
605
- return '';
606
- }
607
-
608
- /**
609
- * @name getResponse
610
- * Read response data and decodes the slip packet, then parses
611
- * out the value/data and returns as a tuple of (value, data) where
612
- * each is a list of bytes
613
- */
614
- async getResponse(opcode, timeout=DEFAULT_TIMEOUT) {
615
- this.readTimeout = timeout;
616
- let packet;
617
- let packetLength = 0;
618
- let resp, opRet, lenRet, val, data;
619
- for (let i = 0; i < 100; i++) {
620
- try {
621
- packet = await this.readPacket();
622
- } catch(e) {
623
- this.debugMsg(1, "Timed out after " + this.readTimeout + " milliseconds");
624
- return [null, null];
625
- }
626
-
627
- if (packet.length < 8) {
628
- continue;
629
- }
630
-
631
- [resp, opRet, lenRet, val] = struct.unpack('<BBHI', packet.slice(0, 8));
632
- if (resp != 1) {
633
- continue;
634
- }
635
- data = packet.slice(8);
636
- if (opcode == null || opRet == opcode) {
637
- return [val, data];
638
- }
639
- if (data[0] != 0 && data[1] == ROM_INVALID_RECV_MSG) {
640
- inputBuffer = [];
641
- throw("Invalid (unsupported) command " + this.toHex(opcode));
642
- }
643
- }
644
- throw("Response doesn't match request");
645
- };
646
-
647
- /**
648
- * @name read
649
- * Read response data and decodes the slip packet.
650
- * Keeps reading until we hit the timeout or get
651
- * a packet closing byte
652
- */
653
- async readBuffer(timeout=DEFAULT_TIMEOUT) {
654
- this.readTimeout = timeout;
655
- let packet;
656
- try {
657
- packet = await this.readPacket();
658
- } catch(e) {
659
- this.debugMsg(1, "Timed out after " + this.readTimeout + " milliseconds");
660
- return null;
661
- }
662
-
663
- return packet;
664
- };
665
-
666
-
667
- /**
668
- * @name checksum
669
- * Calculate checksum of a blob, as it is defined by the ROM
670
- */
671
- checksum(data, state=ESP_CHECKSUM_MAGIC) {
672
- for (let b of data) {
673
- state ^= b;
674
- }
675
- return state;
676
- };
677
-
678
- setPortBaudRate(baud) {
679
- if (this.getChromeVersion() < 86) {
680
- port.baudrate = baud;
681
- } else {
682
- port.baudRate = baud;
683
- }
684
- }
685
-
686
- getPortBaudRate() {
687
- if (this.getChromeVersion() < 86) {
688
- return port.baudrate;
689
- }
690
- return port.baudRate;
691
- }
692
-
693
- async setBaudrate(baud) {
694
- if (this._chipfamily == ESP8266) {
695
- this.logMsg("Baud rate can only change on ESP32 and ESP32-S2");
696
- } else {
697
- this.logMsg("Attempting to change baud rate to " + baud + "...");
698
- try {
699
- // stub takes the new baud rate and the old one
700
- let oldBaud = this.IS_STUB ? this.getPortBaudRate() : 0;
701
- let buffer = struct.pack("<II", baud, oldBaud);
702
- await this.checkCommand(ESP_CHANGE_BAUDRATE, buffer);
703
- this.setPortBaudRate(baud);
704
- await this.sleep(50);
705
- //inputBuffer = [];
706
- this.logMsg("Changed baud rate to " + baud);
707
- } catch (e) {
708
- throw("Unable to change the baud rate, please try setting the connection speed from " + baud + " to 115200 and reconnecting.");
709
- }
710
- }
711
- };
712
-
713
- /**
714
- * @name sync
715
- * Put into ROM bootload mode & attempt to synchronize with the
716
- * ESP ROM bootloader, we will retry a few times
717
- */
718
- async sync() {
719
- this.logMsg("Performing sync...")
720
- for (let i = 0; i < 5; i++) {
721
- inputBuffer = []
722
- let response = await this._sync();
723
- if (response) {
724
- await this.sleep(100);
725
- this.logMsg("Successfully synced.")
726
- return true;
727
- }
728
- await this.sleep(100);
729
- }
730
-
731
- throw("Couldn't sync to ESP. Try resetting.");
732
- };
733
-
734
- /**
735
- * @name _sync
736
- * Perform a soft-sync using AT sync packets, does not perform
737
- * any hardware resetting
738
- */
739
- async _sync() {
740
- await this.command(ESP_SYNC, SYNC_PACKET);
741
- let [val, data] = await this.getResponse(ESP_SYNC, SYNC_TIMEOUT);
742
- this.syncStubDetected = (val === 0 ? 1 : 0);
743
- for (let i = 0; i < 8; i++) {
744
- let [val, data] = await this.getResponse(ESP_SYNC, SYNC_TIMEOUT);
745
- this.syncStubDetected &= (val === 0 ? 1 : 0);
746
- if (data === null) {
747
- continue;
748
- }
749
- if (data.length > 1 && data[0] == 0 && data[1] == 0) {
750
- return true;
751
- }
752
- }
753
- return false;
754
- };
755
-
756
- /**
757
- * @name getFlashWriteSize
758
- * Get the Flash write size based on the chip
759
- */
760
- getFlashWriteSize() {
761
- return FLASH_WRITE_SIZE;
762
- };
763
-
764
- /**
765
- * @name flashData
766
- * Program a full, uncompressed binary file into SPI Flash at
767
- * a given offset. If an ESP32 and md5 string is passed in, will also
768
- * verify memory. ESP8266 does not have checksum memory verification in
769
- * ROM
770
- */
771
- async flashData(binaryData, offset=0, part=0) {
772
- let filesize = binaryData.byteLength;
773
- this.logMsg("\nWriting data with filesize: " + filesize);
774
- let blocks = await this.flashBegin(filesize, offset);
775
- let block = [];
776
- let seq = 0;
777
- let written = 0;
778
- let address = offset;
779
- let position = 0;
780
- let stamp = Date.now();
781
- let flashWriteSize = this.getFlashWriteSize();
782
-
783
- while (filesize - position > 0) {
784
- let percentage = Math.floor(100 * (seq + 1) / blocks);
785
- /*this.logMsg(
786
- "Writing at " + this.toHex(address + seq * flashWriteSize, 8) + "... (" + percentage + " %)"
787
- );*/
788
- if (this.updateProgress !== null) {
789
- this.updateProgress(part, percentage);
790
- }
791
- if (filesize - position >= flashWriteSize) {
792
- block = Array.from(new Uint8Array(binaryData, position, flashWriteSize));
793
- } else {
794
- // Pad the last block
795
- block = Array.from(new Uint8Array(binaryData, position, filesize - position));
796
- block = block.concat(new Array(flashWriteSize - block.length).fill(0xFF));
797
- }
798
- await this.flashBlock(block, seq);
799
- seq += 1;
800
- written += block.length;
801
- position += flashWriteSize;
802
- }
803
- this.logMsg("Took " + (Date.now() - stamp) + "ms to write " + filesize + " bytes");
804
- };
805
-
806
- /**
807
- * @name flashDeflBegin
808
- * Start downloading compressed data to Flash (performs an erase)
809
- * Returns number of blocks (size FLASH_WRITE_SIZE) to write.
810
- */
811
- async flashDeflBegin(size, compsize, offset) {
812
- let params;
813
- let flashWriteSize = this.getFlashWriteSize();
814
- let numBlocks = Math.floor((compsize + flashWriteSize - 1) / flashWriteSize);
815
- let eraseBlocks = Math.floor((size + flashWriteSize - 1) / flashWriteSize);
816
-
817
- let stamp = Date.now()
818
- let writeSize, timeout;
819
- if (this.IS_STUB) {
820
- writeSize = size // stub expects number of bytes here, manages erasing internally
821
- timeout = DEFAULT_TIMEOUT
822
- } else {
823
- writeSize = eraseBlocks * self.FLASH_WRITE_SIZE // ROM expects rounded up to erase block size
824
- timeout = this.timeoutPerMb(ERASE_REGION_TIMEOUT_PER_MB, writeSize);
825
- }
826
- this.logMsg("Compressed " + size + " bytes to " + compsize + "...")
827
- params = struct.pack(
828
- "<IIII", writeSize, numBlocks, flashWriteSize, offset
829
- );
830
- if ([ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily) && !this.IS_STUB) {
831
- params = params.concat(struct.pack("<I", 0));
832
- }
833
-
834
- await this.checkCommand(ESP_FLASH_DEFL_BEGIN, params, 0, timeout);
835
-
836
- if (size != 0 && !this.IS_STUB) {
837
- // (stub erases as it writes, but ROM loaders erase on begin)
838
- this.logMsg("Took " + (Date.now() - stamp) + "ms to erase flash block");
839
- }
840
- return numBlocks;
841
- }
842
-
843
- /**
844
- * @name flashDeflBlock
845
- * Write block to flash, send compressed
846
- */
847
- async flashDeflBlock(data, seq, timeout=DEFAULT_TIMEOUT) {
848
- await this.checkCommand(
849
- ESP_FLASH_DEFL_DATA,
850
- struct.pack("<IIII", data.length, seq, 0, 0).concat(data),
851
- this.checksum(data),
852
- timeout,
853
- );
854
- };
855
-
856
- /**
857
- * @name flashDeflFinish
858
- * Write block to flash, send compressed
859
- */
860
- async flashDeflFinish(reboot=false) {
861
- if (!reboot && !this.IS_STUB) {
862
- // skip sending flash_finish to ROM loader, as this
863
- // exits the bootloader. Stub doesn't do this.
864
- return;
865
- }
866
- let pkt = struct.pack('<I', reboot ? 0 : 1);
867
- await this.checkCommand(ESP_FLASH_DEFL_END, pkt);
868
- };
869
-
870
- /**
871
- * @name flashBegin
872
- * Prepare for flashing by attaching SPI chip and erasing the
873
- * number of blocks requred.
874
- */
875
- async flashBegin(size=0, offset=0, encrypted=false) {
876
- let buffer;
877
- let flashWriteSize = this.getFlashWriteSize();
878
- if (!this.IS_STUB) {
879
- if ([ESP32, ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily)) {
880
- await this.checkCommand(ESP_SPI_ATTACH, new Array(8).fill(0));
881
- }
882
- }
883
- //let flashId = await this.flashId();
884
-
885
- if (this._chipfamily == ESP32) {
886
- // We are hardcoded for 4MB flash on ESP32
887
- buffer = struct.pack(
888
- "<IIIIII", 0, this._flashsize, 0x10000, 4096, 256, 0xFFFF
889
- )
890
- await this.checkCommand(ESP_SPI_SET_PARAMS, buffer);
891
- }
892
- let numBlocks = Math.floor((size + flashWriteSize - 1) / flashWriteSize);
893
- let eraseSize = this.getEraseSize(offset, size);
894
-
895
- let timeout;
896
- if (this.IS_STUB) {
897
- timeout = DEFAULT_TIMEOUT;
898
- } else {
899
- timeout = this.timeoutPerMb(ERASE_REGION_TIMEOUT_PER_MB, size);
900
- }
901
-
902
- let stamp = Date.now();
903
- buffer = struct.pack(
904
- "<IIII", eraseSize, numBlocks, flashWriteSize, offset
905
- );
906
- if ([ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily) && !this.IS_STUB) {
907
- buffer = buffer.concat(struct.pack(
908
- "<I", encrypted ? 1 : 0
909
- ));
910
- }
911
- this.logMsg(
912
- "Erase size " + eraseSize + ", blocks " + numBlocks + ", block size " + flashWriteSize + ", offset " + this.toHex(offset, 4) + ", encrypted " + (encrypted ? "yes" : "no")
913
- );
914
- await this.checkCommand(ESP_FLASH_BEGIN, buffer, 0, timeout);
915
- if (size != 0 && !this.IS_STUB) {
916
- this.logMsg("Took " + (Date.now() - stamp) + "ms to erase " + numBlocks + " bytes");
917
- }
918
- return numBlocks;
919
- };
920
-
921
- /**
922
- * @name flashBlock
923
- * Send one block of data to program into SPI Flash memory
924
- */
925
- async flashBlock(data, seq, timeout=DEFAULT_TIMEOUT) {
926
- await this.checkCommand(
927
- ESP_FLASH_DATA,
928
- struct.pack("<IIII", data.length, seq, 0, 0).concat(data),
929
- this.checksum(data),
930
- timeout,
931
- );
932
- };
933
-
934
- async flashFinish() {
935
- let buffer = struct.pack('<I', 1);
936
- await this.checkCommand(ESP_FLASH_END, buffer);
937
- };
938
-
939
- /**
940
- * @name runSpiflashCommand
941
- * Run an arbitrary SPI flash command.
942
- * This function uses the "USR_COMMAND" functionality in the ESP
943
- * SPI hardware, rather than the precanned commands supported by
944
- * hardware. So the value of spiflash_command is an actual command
945
- * byte, sent over the wire.
946
- * After writing command byte, writes 'data' to MOSI and then
947
- * reads back 'read_bits' of reply on MISO. Result is a number.
948
- */
949
- async runSpiflashCommand(spiflashCommand, data=[], readBits=0, addr=null, addrLen=0, dummyLen=0) {
950
- let chipType = await this.chipType();
951
- let chipInfo = this.getChipInfo(chipType);
952
-
953
- // SPI_USR register flags
954
- const SPI_USR_COMMAND = (1 << 31)
955
- const SPI_USR_ADDR = (1 << 30)
956
- const SPI_USR_DUMMY = (1 << 29)
957
- const SPI_USR_MISO = (1 << 28)
958
- const SPI_USR_MOSI = (1 << 27)
959
-
960
- // SPI registers, base address differs ESP32* vs 8266
961
- const base = chipInfo.spiRegBase
962
- const SPI_CMD_REG = base + 0x00
963
- const SPI_ADDR_REG = base + 0x04
964
- const SPI_USR_REG = base + chipInfo.spiUsrOffs
965
- const SPI_USR1_REG = base + chipInfo.spiUsr1Offs
966
- const SPI_USR2_REG = base + chipInfo.spiUsr2Offs
967
- const SPI_W0_REG = base + chipInfo.spiW0Offs
968
-
969
- // shift values
970
- const SPI_USR2_COMMAND_LEN_SHIFT = 28
971
- const SPI_USR_ADDR_LEN_SHIFT = 26
972
-
973
- // SPI peripheral "command" bitmasks for SPI_CMD_REG
974
- const SPI_CMD_USR = (1 << 18);
975
-
976
- let setDataLengths;
977
- let flags;
978
- //following two registers are ESP32 and later chips only
979
- if (chipInfo.spiMosiDlenOffs != null) {
980
- // ESP32 and later chips have a more sophisticated way to set up "user" commands
981
- setDataLengths = async function(mosi_bits, miso_bits) {
982
- const SPI_MOSI_DLEN_REG = base + chipInfo.spiMosiDlenOffs;
983
- const SPI_MISO_DLEN_REG = base + chipInfo.spiMisoDlenOffs;
984
- if (mosi_bits > 0) {
985
- await this.writeRegister(SPI_MOSI_DLEN_REG, mosi_bits - 1);
986
- }
987
- if (miso_bits > 0) {
988
- await this.writeRegister(SPI_MISO_DLEN_REG, miso_bits - 1);
989
- }
990
- flags = 0;
991
- if (dummyLen > 0) {
992
- flags |= (dummyLen - 1);
993
- }
994
- if (addrLen > 0) {
995
- flags |= (addrLen - 1) << SPI_USR_ADDR_LEN_SHIFT;
996
- }
997
- if (flags) {
998
- await this.writeRegister(SPI_USR1_REG, flags);
999
- }
1000
- }
1001
- } else {
1002
- setDataLengths = async function (mosi_bits, miso_bits) {
1003
- const SPI_DATA_LEN_REG = SPI_USR1_REG;
1004
- const SPI_MOSI_BITLEN_S = 17;
1005
- const SPI_MISO_BITLEN_S = 8;
1006
- let mosi_mask = (mosi_bits == 0) ? 0 : (mosi_bits - 1);
1007
- let miso_mask = (miso_bits == 0) ? 0 : (miso_bits - 1);
1008
- flags = (miso_mask << SPI_MISO_BITLEN_S) | (mosi_mask << SPI_MOSI_BITLEN_S);
1009
- if (dummyLen > 0) {
1010
- flags |= (dummyLen - 1);
1011
- }
1012
- if (addrLen > 0) {
1013
- flags |= (addrLen - 1) << SPI_USR_ADDR_LEN_SHIFT;
1014
- }
1015
- await this.writeRegister(SPI_DATA_LEN_REG, flags);
1016
- }
1017
- }
1018
- setDataLengths = setDataLengths.bind(this);
1019
- if (readBits > 32) {
1020
- throw new FatalError("Reading more than 32 bits back from a SPI flash operation is unsupported")
1021
- }
1022
- if (data.length > 64) {
1023
- throw new FatalError("Writing more than 64 bytes of data with one SPI command is unsupported")
1024
- }
1025
-
1026
- let dataBits = data.length * 8
1027
- let old_spi_usr = await this.readRegister(SPI_USR_REG);
1028
- let old_spi_usr2 = await this.readRegister(SPI_USR2_REG);
1029
- flags = SPI_USR_COMMAND;
1030
- if (readBits > 0) {
1031
- flags |= SPI_USR_MISO;
1032
- }
1033
- if (dataBits > 0) {
1034
- flags |= SPI_USR_MOSI;
1035
- }
1036
- if (addrLen > 0) {
1037
- flags |= SPI_USR_ADDR;
1038
- }
1039
- if (dummyLen > 0) {
1040
- flags |= SPI_USR_DUMMY;
1041
- }
1042
- await setDataLengths(dataBits, readBits);
1043
- await this.writeRegister(SPI_USR_REG, flags)
1044
- await this.writeRegister(SPI_USR2_REG,
1045
- (7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflashCommand)
1046
- if (addr != null && addrLen > 0) {
1047
- await this.writeRegister(SPI_ADDR_REG, addr);
1048
- }
1049
- if (dataBits == 0) {
1050
- await this.writeRegister(SPI_W0_REG, 0) // clear data register before we read it
1051
- } else {
1052
- data = data.concat(new Array(4 - data.length).fill(0)); // pad to 32-bit multiple
1053
- let words = struct.unpack("I" * Math.floor(data.length / 4), data);
1054
- let next_reg = SPI_W0_REG;
1055
- for (let word of words) {
1056
- await this.writeRegister(next_reg, word)
1057
- next_reg += 4;
1058
- }
1059
- }
1060
- await this.writeRegister(SPI_CMD_REG, SPI_CMD_USR)
1061
-
1062
- let waitDone = async function() {
1063
- for (let i = 0; i < 10; i++) {
1064
- if ((await this.readRegister(SPI_CMD_REG) & SPI_CMD_USR) == 0) {
1065
- return
1066
- }
1067
- }
1068
- throw new FatalError("SPI command did not complete in time")
1069
- }
1070
- waitDone = waitDone.bind(this);
1071
- await waitDone();
1072
-
1073
- let status = await this.readRegister(SPI_W0_REG);
1074
- // restore some SPI controller registers
1075
- await this.writeRegister(SPI_USR_REG, old_spi_usr);
1076
- await this.writeRegister(SPI_USR2_REG, old_spi_usr2);
1077
- return status
1078
-
1079
- }
1080
-
1081
- async flashId() {
1082
- const SPIFLASH_RDID = 0x9F;
1083
-
1084
- return await this.runSpiflashCommand(SPIFLASH_RDID, [], 24);
1085
- }
1086
-
1087
- /**
1088
- * @name getEraseSize
1089
- * Calculate an erase size given a specific size in bytes.
1090
- * Provides a workaround for the bootloader erase bug on ESP8266.
1091
- */
1092
- getEraseSize(offset, size) {
1093
- if (this._chipfamily != ESP8266 || this.IS_STUB) {
1094
- return size;
1095
- }
1096
- let sectorsPerBlock = 16;
1097
- let sectorSize = FLASH_SECTOR_SIZE;
1098
- let numSectors = Math.floor((size + sectorSize - 1) / sectorSize);
1099
- let startSector = Math.floor(offset / sectorSize);
1100
-
1101
- let headSectors = sectorsPerBlock - (startSector % sectorsPerBlock);
1102
- if (numSectors < headSectors) {
1103
- headSectors = numSectors;
1104
- }
1105
-
1106
- if (numSectors < 2 * headSectors) {
1107
- return Math.floor((numSectors + 1) / 2 * sectorSize);
1108
- }
1109
-
1110
- return (numSectors - headSectors) * sectorSize;
1111
- };
1112
-
1113
- /**
1114
- * @name memBegin (592)
1115
- * Start downloading an application image to RAM
1116
- */
1117
- async memBegin(size, blocks, blocksize, offset) {
1118
- if (this.IS_STUB) {
1119
- let stub = await this.getStubCode();
1120
- let load_start = offset;
1121
- let load_end = offset + size;
1122
- for (let [start, end] of [
1123
- [stub.data_start, stub.data_start + stub.data.length],
1124
- [stub.text_start, stub.text_start + stub.text.length]]
1125
- ) {
1126
- if (load_start < end && load_end > start) {
1127
- throw("Software loader is resident at " + this.toHex(start, 8) + "-" + this.toHex(end, 8) + ". " +
1128
- "Can't load binary at overlapping address range " + this.toHex(load_start, 8) + "-" + this.toHex(load_end, 8) + ". " +
1129
- "Try changing the binary loading address.");
1130
- }
1131
- }
1132
- }
1133
-
1134
- return this.checkCommand(ESP_MEM_BEGIN, struct.pack('<IIII', size, blocks, blocksize, offset));
1135
- }
1136
-
1137
- /**
1138
- * @name memBlock (609)
1139
- * Send a block of an image to RAM
1140
- */
1141
- async memBlock(data, seq) {
1142
- return await this.checkCommand(
1143
- ESP_MEM_DATA,
1144
- struct.pack('<IIII', data.length, seq, 0, 0).concat(data),
1145
- this.checksum(data)
1146
- );
1147
- }
1148
-
1149
- /**
1150
- * @name memFinish (615)
1151
- * Leave download mode and run the application
1152
- *
1153
- * Sending ESP_MEM_END usually sends a correct response back, however sometimes
1154
- * (with ROM loader) the executed code may reset the UART or change the baud rate
1155
- * before the transmit FIFO is empty. So in these cases we set a short timeout and
1156
- * ignore errors.
1157
- */
1158
- async memFinish(entrypoint=0) {
1159
- let timeout = this.IS_STUB ? DEFAULT_TIMEOUT : MEM_END_ROM_TIMEOUT;
1160
- let data = struct.pack('<II', parseInt(entrypoint == 0), entrypoint);
1161
- try {
1162
- return await this.checkCommand(ESP_MEM_END, data, 0, timeout);
1163
- } catch (e) {
1164
- if (this.IS_STUB) {
1165
- throw(e);
1166
- }
1167
- }
1168
- }
1169
-
1170
- async getStubCode() {
1171
- let chipType = await this.chipType();
1172
- let chipInfo = this.getChipInfo(chipType);
1173
-
1174
- let response = await fetch('stubs/' + chipInfo.stubFile + '.json');
1175
- let stubcode = await response.json();
1176
-
1177
- // Base64 decode the text and data
1178
- stubcode.text = toByteArray(atob(stubcode.text));
1179
- stubcode.data = toByteArray(atob(stubcode.data));
1180
- return stubcode;
1181
- }
1182
-
1183
- getStubLoaderClass() {
1184
- // Based on current chip, we return the appropriate stub loader class
1185
- }
1186
-
1187
- getRomClass() {
1188
- // Based on current chip, we return the appropriate Rom class
1189
- }
1190
-
1191
- async runStub(stub=null) {
1192
- if (stub === null) {
1193
- stub = await this.getStubCode();
1194
- }
1195
-
1196
- if (this.syncStubDetected || this.IS_STUB) {
1197
- this.logMsg("Stub is already running. No upload is necessary.");
1198
- return this.stubClass;
1199
- }
1200
-
1201
- let ramBlock = ESP_RAM_BLOCK;
1202
- // We're transferring over USB, right?
1203
- if ([ESP32S2, ESP32S3, ESP32C3].includes(this._chipfamily)) {
1204
- ramBlock = USB_RAM_BLOCK;
1205
- }
1206
-
1207
- // Upload
1208
- this.logMsg("Uploading stub...")
1209
- for (let field of ['text', 'data']) {
1210
- if (Object.keys(stub).includes(field)) {
1211
- let offset = stub[field + "_start"];
1212
- let length = stub[field].length;
1213
- let blocks = Math.floor((length + ramBlock - 1) / ramBlock);
1214
- await this.memBegin(length, blocks, ramBlock, offset);
1215
- for (let seq of Array(blocks).keys()) {
1216
- let fromOffs = seq * ramBlock;
1217
- let toOffs = fromOffs + ramBlock;
1218
- if (toOffs > length) {
1219
- toOffs = length;
1220
- }
1221
- await this.memBlock(stub[field].slice(fromOffs, toOffs), seq);
1222
- }
1223
- }
1224
- }
1225
- this.logMsg("Running stub...")
1226
- await this.memFinish(stub['entry']);
1227
-
1228
- let p = await this.readBuffer(500);
1229
- p = String.fromCharCode(...p);
1230
-
1231
- if (p != 'OHAI') {
1232
- throw "Failed to start stub. Unexpected response: " + p;
1233
- }
1234
- this.logMsg("Stub is now running...");
1235
- let stubLoader = new EspStubLoader({
1236
- updateProgress: this.updateProgress,
1237
- logMsg: this.logMsg,
1238
- debugMsg: this._debugMsg,
1239
- debug: this.debug,
1240
- });
1241
- stubLoader.stubClass = stubLoader;
1242
- return stubLoader;
1243
- }
1244
- }
1245
-
1246
- class EspStubLoader extends EspLoader {
1247
- /*
1248
- The Stubloader has commands that run on the uploaded Stub Code in RAM
1249
- rather than built in commands.
1250
- */
1251
- constructor(params) {
1252
- super(params);
1253
- this.IS_STUB = true;
1254
- }
1255
- /**
1256
- * @name eraseFlash
1257
- * depending on flash chip model the erase may take this long (maybe longer!)
1258
- */
1259
- async eraseFlash() {
1260
- await this.checkCommand(ESP_ERASE_FLASH, [], 0, CHIP_ERASE_TIMEOUT);
1261
- };
1262
-
1263
- /**
1264
- * @name getFlashWriteSize
1265
- * Get the Flash write size based on the chip
1266
- */
1267
- getFlashWriteSize() {
1268
- return STUBLOADER_FLASH_WRITE_SIZE;
1269
- };
1270
- }
1271
-
1272
- class Esp32StubLoader extends EspStubLoader {
1273
-
1274
- }
1275
-
1276
- /*
1277
- Represents error when NVS Partition size given is insufficient
1278
- to accomodate the data in the given csv file
1279
- */
1280
- class SlipReadError extends Error {
1281
- constructor(message) {
1282
- super(message);
1283
- this.name = "SlipReadError";
1284
- }
1285
- }
1286
-
1287
- class FatalError extends Error {
1288
- constructor(message) {
1289
- super(message);
1290
- this.name = "FatalError";
1291
- }
1292
- }