tasmota-webserial-esptool 6.1.0 → 6.1.2

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 (70) hide show
  1. package/.github/workflows/build_upload.yml +8 -9
  2. package/.github/workflows/ci.yml +4 -3
  3. package/README.md +1 -5
  4. package/dist/const.js +2 -2
  5. package/dist/esp_loader.js +2 -2
  6. package/dist/stubs/esp32.json +2 -2
  7. package/dist/stubs/esp32c2.json +2 -2
  8. package/dist/stubs/esp32c3.json +2 -2
  9. package/dist/stubs/esp32c6.json +2 -2
  10. package/dist/stubs/esp32h2.json +2 -2
  11. package/dist/stubs/esp32s2.json +2 -2
  12. package/dist/stubs/esp32s3.json +4 -4
  13. package/dist/stubs/esp8266.json +7 -1
  14. package/dist/web/esp32-m40MFH7J.js +1 -0
  15. package/{js/modules/esp32c2-f0222390.js → dist/web/esp32c2-HzlV3wSg.js} +1 -1
  16. package/dist/web/esp32c3-_TitTxJz.js +1 -0
  17. package/dist/web/esp32c6-sCbnPu6P.js +1 -0
  18. package/dist/web/esp32h2-aXM-pq3U.js +1 -0
  19. package/dist/web/esp32s2-AioFXBxU.js +1 -0
  20. package/dist/web/esp32s3-M5610giH.js +1 -0
  21. package/dist/web/esp8266-BsRiKnq5.js +1 -0
  22. package/dist/web/index.js +1 -1
  23. package/index.html +1 -1
  24. package/js/modules/esp32-m40MFH7J.js +1 -0
  25. package/{dist/web/esp32c2-f0222390.js → js/modules/esp32c2-HzlV3wSg.js} +1 -1
  26. package/js/modules/esp32c3-_TitTxJz.js +1 -0
  27. package/js/modules/esp32c6-sCbnPu6P.js +1 -0
  28. package/js/modules/esp32h2-aXM-pq3U.js +1 -0
  29. package/js/modules/esp32s2-AioFXBxU.js +1 -0
  30. package/js/modules/esp32s3-M5610giH.js +1 -0
  31. package/js/modules/esp8266-BsRiKnq5.js +1 -0
  32. package/js/modules/esptool.js +1 -1
  33. package/js/script.js +5 -4
  34. package/package.json +13 -13
  35. package/rollup.config.js +1 -1
  36. package/script/build +1 -2
  37. package/src/const.ts +4 -4
  38. package/src/esp_loader.ts +51 -51
  39. package/src/stubs/esp32.json +2 -2
  40. package/src/stubs/esp32c2.json +2 -2
  41. package/src/stubs/esp32c3.json +3 -3
  42. package/src/stubs/esp32c6.json +3 -3
  43. package/src/stubs/esp32h2.json +3 -3
  44. package/src/stubs/esp32s2.json +3 -3
  45. package/src/stubs/esp32s3.json +5 -5
  46. package/src/stubs/esp8266.json +7 -1
  47. package/dist/web/esp32-d51f885c.js +0 -1
  48. package/dist/web/esp32c3-9f5fd05b.js +0 -1
  49. package/dist/web/esp32c6-e911f438.js +0 -1
  50. package/dist/web/esp32h2-19e099dc.js +0 -1
  51. package/dist/web/esp32s2-da1a4fa1.js +0 -1
  52. package/dist/web/esp32s3-d79eec99.js +0 -1
  53. package/dist/web/esp8266-144419c0.js +0 -1
  54. package/js/esptool.js +0 -1396
  55. package/js/modules/esp32-d51f885c.js +0 -1
  56. package/js/modules/esp32c3-9f5fd05b.js +0 -1
  57. package/js/modules/esp32c6-e911f438.js +0 -1
  58. package/js/modules/esp32h2-19e099dc.js +0 -1
  59. package/js/modules/esp32s2-da1a4fa1.js +0 -1
  60. package/js/modules/esp32s3-d79eec99.js +0 -1
  61. package/js/modules/esp8266-144419c0.js +0 -1
  62. package/script/stubgen.py +0 -47
  63. package/stubs/esp32.json +0 -7
  64. package/stubs/esp32c2.json +0 -7
  65. package/stubs/esp32c3.json +0 -7
  66. package/stubs/esp32c6.json +0 -7
  67. package/stubs/esp32h2.json +0 -7
  68. package/stubs/esp32s2.json +0 -7
  69. package/stubs/esp32s3.json +0 -7
  70. 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
- }