tasmota-webserial-esptool 6.5.4 → 7.0.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/README.md +4 -3
- package/READ_FLASH_FEATURE.md +130 -0
- package/css/light.css +11 -0
- package/css/style.css +213 -45
- package/dist/const.d.ts +41 -2
- package/dist/const.js +100 -2
- package/dist/esp_loader.d.ts +27 -3
- package/dist/esp_loader.js +377 -17
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -2
- package/dist/partition.d.ts +26 -0
- package/dist/partition.js +129 -0
- package/dist/stubs/esp32.json +4 -4
- package/dist/stubs/esp32c2.json +4 -4
- package/dist/stubs/esp32c3.json +4 -4
- package/dist/stubs/esp32c5.json +4 -4
- package/dist/stubs/esp32c6.json +4 -4
- package/dist/stubs/esp32c61.json +4 -4
- package/dist/stubs/esp32h2.json +4 -4
- package/dist/stubs/esp32p4.json +4 -4
- package/dist/stubs/esp32p4r3.json +4 -4
- package/dist/stubs/esp32s2.json +4 -4
- package/dist/stubs/esp32s3.json +4 -4
- package/dist/stubs/esp8266.json +3 -3
- package/dist/stubs/index.d.ts +1 -1
- package/dist/stubs/index.js +7 -1
- package/dist/web/esp32-CijhsJH1.js +1 -0
- package/dist/web/esp32c2-C17SM4gO.js +1 -0
- package/dist/web/esp32c3-DxRGijbg.js +1 -0
- package/dist/web/esp32c5-3mDOIGa4.js +1 -0
- package/dist/web/esp32c6-h6U0SQTm.js +1 -0
- package/dist/web/esp32c61-BKtexhPZ.js +1 -0
- package/dist/web/esp32h2-RtuWSEmP.js +1 -0
- package/dist/web/esp32p4-5nkIjxqJ.js +1 -0
- package/dist/web/esp32p4r3-CpHBYEwI.js +1 -0
- package/dist/web/esp32s2-IiDBtXxo.js +1 -0
- package/dist/web/esp32s3-6yv5yxum.js +1 -0
- package/dist/web/esp8266-CUwxJpGa.js +1 -0
- package/dist/web/index.js +1 -1
- package/index.html +158 -34
- package/js/modules/esp32-CijhsJH1.js +1 -0
- package/js/modules/esp32c2-C17SM4gO.js +1 -0
- package/js/modules/esp32c3-DxRGijbg.js +1 -0
- package/js/modules/esp32c5-3mDOIGa4.js +1 -0
- package/js/modules/esp32c6-h6U0SQTm.js +1 -0
- package/js/modules/esp32c61-BKtexhPZ.js +1 -0
- package/js/modules/esp32h2-RtuWSEmP.js +1 -0
- package/js/modules/esp32p4-5nkIjxqJ.js +1 -0
- package/js/modules/esp32p4r3-CpHBYEwI.js +1 -0
- package/js/modules/esp32s2-IiDBtXxo.js +1 -0
- package/js/modules/esp32s3-6yv5yxum.js +1 -0
- package/js/modules/esp8266-CUwxJpGa.js +1 -0
- package/js/modules/esptool.js +1 -1
- package/js/script.js +456 -11
- package/package.json +6 -6
- package/src/const.ts +107 -3
- package/src/esp_loader.ts +492 -18
- package/src/index.ts +3 -1
- package/src/partition.ts +155 -0
- package/src/stubs/README.md +1 -1
- package/src/stubs/esp32.json +4 -4
- package/src/stubs/esp32c2.json +4 -4
- package/src/stubs/esp32c3.json +4 -4
- package/src/stubs/esp32c5.json +4 -4
- package/src/stubs/esp32c6.json +4 -4
- package/src/stubs/esp32c61.json +4 -4
- package/src/stubs/esp32h2.json +4 -4
- package/src/stubs/esp32p4.json +4 -4
- package/src/stubs/esp32p4r3.json +4 -4
- package/src/stubs/esp32s2.json +4 -4
- package/src/stubs/esp32s3.json +4 -4
- package/src/stubs/esp8266.json +3 -3
- package/src/stubs/index.ts +14 -2
- package/BUGFIX_GET_SECURITY_INFO.md +0 -126
- package/IMPLEMENTATION_SUMMARY.md +0 -232
- package/SECURITY_INFO_EXPLANATION.md +0 -145
- package/dist/web/esp32-BNIFdu1P.js +0 -1
- package/dist/web/esp32c2-BqxquOKw.js +0 -1
- package/dist/web/esp32c3-BOOqe8me.js +0 -1
- package/dist/web/esp32c5-mcj52-K1.js +0 -1
- package/dist/web/esp32c6-Cg5qYgg7.js +0 -1
- package/dist/web/esp32c61-CzCdsydk.js +0 -1
- package/dist/web/esp32h2-DZa_lpff.js +0 -1
- package/dist/web/esp32p4-DyGqUAeZ.js +0 -1
- package/dist/web/esp32p4r3-Cle9QJmZ.js +0 -1
- package/dist/web/esp32s2-Bk4mqADi.js +0 -1
- package/dist/web/esp32s3-Df3OUCOC.js +0 -1
- package/dist/web/esp8266-CQFcqJ_a.js +0 -1
- package/js/modules/esp32-BNIFdu1P.js +0 -1
- package/js/modules/esp32c2-BqxquOKw.js +0 -1
- package/js/modules/esp32c3-BOOqe8me.js +0 -1
- package/js/modules/esp32c5-mcj52-K1.js +0 -1
- package/js/modules/esp32c6-Cg5qYgg7.js +0 -1
- package/js/modules/esp32c61-CzCdsydk.js +0 -1
- package/js/modules/esp32h2-DZa_lpff.js +0 -1
- package/js/modules/esp32p4-DyGqUAeZ.js +0 -1
- package/js/modules/esp32p4r3-Cle9QJmZ.js +0 -1
- package/js/modules/esp32s2-Bk4mqADi.js +0 -1
- package/js/modules/esp32s3-Df3OUCOC.js +0 -1
- package/js/modules/esp8266-CQFcqJ_a.js +0 -1
package/dist/esp_loader.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="@types/w3c-web-serial" />
|
|
2
|
-
import { CHIP_FAMILY_ESP32, CHIP_FAMILY_ESP32S2, CHIP_FAMILY_ESP32S3, CHIP_FAMILY_ESP32C2, CHIP_FAMILY_ESP32C3, CHIP_FAMILY_ESP32C5, CHIP_FAMILY_ESP32C6, CHIP_FAMILY_ESP32C61, CHIP_FAMILY_ESP32H2, CHIP_FAMILY_ESP32P4, CHIP_FAMILY_ESP8266, MAX_TIMEOUT, DEFAULT_TIMEOUT, ERASE_REGION_TIMEOUT_PER_MB, ESP_CHANGE_BAUDRATE, ESP_CHECKSUM_MAGIC, ESP_FLASH_BEGIN, ESP_FLASH_DATA, ESP_FLASH_END, ESP_MEM_BEGIN, ESP_MEM_DATA, ESP_MEM_END, ESP_READ_REG, ESP_WRITE_REG, ESP_SPI_ATTACH, ESP_SYNC, ESP_GET_SECURITY_INFO, FLASH_SECTOR_SIZE, FLASH_WRITE_SIZE, STUB_FLASH_WRITE_SIZE, MEM_END_ROM_TIMEOUT, ROM_INVALID_RECV_MSG, SYNC_PACKET, SYNC_TIMEOUT, USB_RAM_BLOCK, ESP_ERASE_FLASH, CHIP_ERASE_TIMEOUT, timeoutPerMb, ESP_ROM_BAUD, USB_JTAG_SERIAL_PID, ESP_FLASH_DEFL_BEGIN, ESP_FLASH_DEFL_DATA, ESP_FLASH_DEFL_END, getSpiFlashAddresses, DETECTED_FLASH_SIZES, CHIP_DETECT_MAGIC_REG_ADDR, CHIP_DETECT_MAGIC_VALUES, CHIP_ID_TO_INFO, ESP32P4_EFUSE_BLOCK1_ADDR, SlipReadError, } from "./const";
|
|
2
|
+
import { CHIP_FAMILY_ESP32, CHIP_FAMILY_ESP32S2, CHIP_FAMILY_ESP32S3, CHIP_FAMILY_ESP32C2, CHIP_FAMILY_ESP32C3, CHIP_FAMILY_ESP32C5, CHIP_FAMILY_ESP32C6, CHIP_FAMILY_ESP32C61, CHIP_FAMILY_ESP32H2, CHIP_FAMILY_ESP32H4, CHIP_FAMILY_ESP32H21, CHIP_FAMILY_ESP32P4, CHIP_FAMILY_ESP32S31, CHIP_FAMILY_ESP8266, MAX_TIMEOUT, DEFAULT_TIMEOUT, ERASE_REGION_TIMEOUT_PER_MB, ESP_CHANGE_BAUDRATE, ESP_CHECKSUM_MAGIC, ESP_FLASH_BEGIN, ESP_FLASH_DATA, ESP_FLASH_END, ESP_MEM_BEGIN, ESP_MEM_DATA, ESP_MEM_END, ESP_READ_REG, ESP_WRITE_REG, ESP_SPI_ATTACH, ESP_SYNC, ESP_GET_SECURITY_INFO, FLASH_SECTOR_SIZE, FLASH_WRITE_SIZE, STUB_FLASH_WRITE_SIZE, MEM_END_ROM_TIMEOUT, ROM_INVALID_RECV_MSG, SYNC_PACKET, SYNC_TIMEOUT, USB_RAM_BLOCK, ESP_ERASE_FLASH, ESP_READ_FLASH, CHIP_ERASE_TIMEOUT, FLASH_READ_TIMEOUT, timeoutPerMb, ESP_ROM_BAUD, USB_JTAG_SERIAL_PID, ESP_FLASH_DEFL_BEGIN, ESP_FLASH_DEFL_DATA, ESP_FLASH_DEFL_END, getSpiFlashAddresses, DETECTED_FLASH_SIZES, CHIP_DETECT_MAGIC_REG_ADDR, CHIP_DETECT_MAGIC_VALUES, CHIP_ID_TO_INFO, ESP32P4_EFUSE_BLOCK1_ADDR, SlipReadError, } from "./const";
|
|
3
3
|
import { getStubCode } from "./stubs";
|
|
4
4
|
import { hexFormatter, sleep, slipEncode, toHex } from "./util";
|
|
5
5
|
// @ts-ignore
|
|
@@ -20,18 +20,84 @@ export class ESPLoader extends EventTarget {
|
|
|
20
20
|
this.IS_STUB = false;
|
|
21
21
|
this.connected = true;
|
|
22
22
|
this.flashSize = null;
|
|
23
|
+
this._currentBaudRate = ESP_ROM_BAUD;
|
|
23
24
|
this.state_DTR = false;
|
|
24
25
|
}
|
|
25
26
|
get _inputBuffer() {
|
|
26
27
|
return this._parent ? this._parent._inputBuffer : this.__inputBuffer;
|
|
27
28
|
}
|
|
29
|
+
get _totalBytesRead() {
|
|
30
|
+
return this._parent
|
|
31
|
+
? this._parent._totalBytesRead
|
|
32
|
+
: this.__totalBytesRead || 0;
|
|
33
|
+
}
|
|
34
|
+
set _totalBytesRead(value) {
|
|
35
|
+
if (this._parent) {
|
|
36
|
+
this._parent._totalBytesRead = value;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
this.__totalBytesRead = value;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
detectUSBSerialChip(vendorId, productId) {
|
|
43
|
+
// Common USB-Serial chip vendors and their products
|
|
44
|
+
const chips = {
|
|
45
|
+
0x1a86: {
|
|
46
|
+
// QinHeng Electronics
|
|
47
|
+
0x7523: { name: "CH340", maxBaudrate: 460800 },
|
|
48
|
+
0x55d4: { name: "CH9102", maxBaudrate: 6000000 },
|
|
49
|
+
},
|
|
50
|
+
0x10c4: {
|
|
51
|
+
// Silicon Labs
|
|
52
|
+
0xea60: { name: "CP2102(n)", maxBaudrate: 3000000 },
|
|
53
|
+
0xea70: { name: "CP2105", maxBaudrate: 2000000 },
|
|
54
|
+
0xea71: { name: "CP2108", maxBaudrate: 2000000 },
|
|
55
|
+
},
|
|
56
|
+
0x0403: {
|
|
57
|
+
// FTDI
|
|
58
|
+
0x6001: { name: "FT232R", maxBaudrate: 3000000 },
|
|
59
|
+
0x6010: { name: "FT2232", maxBaudrate: 3000000 },
|
|
60
|
+
0x6011: { name: "FT4232", maxBaudrate: 3000000 },
|
|
61
|
+
0x6014: { name: "FT232H", maxBaudrate: 12000000 },
|
|
62
|
+
0x6015: { name: "FT230X", maxBaudrate: 3000000 },
|
|
63
|
+
},
|
|
64
|
+
0x303a: {
|
|
65
|
+
// Espressif (native USB)
|
|
66
|
+
0x2: { name: "ESP32-S2 Native USB", maxBaudrate: 2000000 },
|
|
67
|
+
0x1001: { name: "ESP32 Native USB", maxBaudrate: 2000000 },
|
|
68
|
+
0x1002: { name: "ESP32 Native USB", maxBaudrate: 2000000 },
|
|
69
|
+
0x4002: { name: "ESP32 Native USB", maxBaudrate: 2000000 },
|
|
70
|
+
0x1000: { name: "ESP32 Native USB", maxBaudrate: 2000000 },
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
const vendor = chips[vendorId];
|
|
74
|
+
if (vendor && vendor[productId]) {
|
|
75
|
+
return vendor[productId];
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
name: `Unknown (VID: 0x${vendorId.toString(16)}, PID: 0x${productId.toString(16)})`,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
28
81
|
async initialize() {
|
|
29
82
|
await this.hardReset(true);
|
|
30
83
|
if (!this._parent) {
|
|
31
84
|
this.__inputBuffer = [];
|
|
85
|
+
this.__totalBytesRead = 0;
|
|
86
|
+
// Detect and log USB-Serial chip info
|
|
87
|
+
const portInfo = this.port.getInfo();
|
|
88
|
+
if (portInfo.usbVendorId && portInfo.usbProductId) {
|
|
89
|
+
const chipInfo = this.detectUSBSerialChip(portInfo.usbVendorId, portInfo.usbProductId);
|
|
90
|
+
this.logger.log(`USB-Serial: ${chipInfo.name} (VID: 0x${portInfo.usbVendorId.toString(16)}, PID: 0x${portInfo.usbProductId.toString(16)})`);
|
|
91
|
+
if (chipInfo.maxBaudrate) {
|
|
92
|
+
this._maxUSBSerialBaudrate = chipInfo.maxBaudrate;
|
|
93
|
+
this.logger.log(`Max baudrate: ${chipInfo.maxBaudrate}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
32
96
|
// Don't await this promise so it doesn't block rest of method.
|
|
33
97
|
this.readLoop();
|
|
34
98
|
}
|
|
99
|
+
// Clear buffer again after starting read loop
|
|
100
|
+
await this.flushSerialBuffers();
|
|
35
101
|
await this.sync();
|
|
36
102
|
// Detect chip type
|
|
37
103
|
await this.detectChip();
|
|
@@ -42,7 +108,7 @@ export class ESPLoader extends EventTarget {
|
|
|
42
108
|
this._efuses[i] = await this.readRegister(AddrMAC + 4 * i);
|
|
43
109
|
}
|
|
44
110
|
this.logger.log(`Chip type ${this.chipName}`);
|
|
45
|
-
|
|
111
|
+
this.logger.debug(`Bootloader flash offset: 0x${FlAddr.flashOffs.toString(16)}`);
|
|
46
112
|
}
|
|
47
113
|
/**
|
|
48
114
|
* Detect chip type using GET_SECURITY_INFO (for newer chips) or magic value (for older chips)
|
|
@@ -79,7 +145,7 @@ export class ESPLoader extends EventTarget {
|
|
|
79
145
|
this.logger.debug(`GET_SECURITY_INFO failed, using magic value detection: ${err}`);
|
|
80
146
|
// Clear input buffer and re-sync to recover from failed command
|
|
81
147
|
this._inputBuffer.length = 0;
|
|
82
|
-
await sleep(
|
|
148
|
+
await sleep(SYNC_TIMEOUT);
|
|
83
149
|
// Re-sync with the chip to ensure clean communication
|
|
84
150
|
try {
|
|
85
151
|
await this.sync();
|
|
@@ -175,7 +241,12 @@ export class ESPLoader extends EventTarget {
|
|
|
175
241
|
if (!value || value.length === 0) {
|
|
176
242
|
continue;
|
|
177
243
|
}
|
|
178
|
-
|
|
244
|
+
// Always read from browser's serial buffer immediately
|
|
245
|
+
// to prevent browser buffer overflow. Don't apply back-pressure here.
|
|
246
|
+
const chunk = Array.from(value);
|
|
247
|
+
Array.prototype.push.apply(this._inputBuffer, chunk);
|
|
248
|
+
// Track total bytes read from serial port
|
|
249
|
+
this._totalBytesRead += value.length;
|
|
179
250
|
}
|
|
180
251
|
}
|
|
181
252
|
catch (err) {
|
|
@@ -202,7 +273,6 @@ export class ESPLoader extends EventTarget {
|
|
|
202
273
|
await this.port.setSignals({ dataTerminalReady: state });
|
|
203
274
|
}
|
|
204
275
|
async hardReset(bootloader = false) {
|
|
205
|
-
this.logger.log("Try hard reset.");
|
|
206
276
|
if (bootloader) {
|
|
207
277
|
// enter flash mode
|
|
208
278
|
if (this.port.getInfo().usbProductId === USB_JTAG_SERIAL_PID) {
|
|
@@ -221,6 +291,7 @@ export class ESPLoader extends EventTarget {
|
|
|
221
291
|
await this.sleep(100);
|
|
222
292
|
await this.setDTR(false);
|
|
223
293
|
await this.setRTS(false);
|
|
294
|
+
this.logger.log("USB MCU reset.");
|
|
224
295
|
}
|
|
225
296
|
else {
|
|
226
297
|
// otherwise, esp chip should be connected to computer via usb-serial
|
|
@@ -233,6 +304,7 @@ export class ESPLoader extends EventTarget {
|
|
|
233
304
|
await this.setRTS(false);
|
|
234
305
|
await this.sleep(50);
|
|
235
306
|
await this.setDTR(false);
|
|
307
|
+
this.logger.log("DTR/RTS USB serial chip reset.");
|
|
236
308
|
}
|
|
237
309
|
}
|
|
238
310
|
else {
|
|
@@ -240,6 +312,7 @@ export class ESPLoader extends EventTarget {
|
|
|
240
312
|
await this.setRTS(true); // EN->LOW
|
|
241
313
|
await this.sleep(100);
|
|
242
314
|
await this.setRTS(false);
|
|
315
|
+
this.logger.log("Hard reset.");
|
|
243
316
|
}
|
|
244
317
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
245
318
|
}
|
|
@@ -290,7 +363,10 @@ export class ESPLoader extends EventTarget {
|
|
|
290
363
|
this.chipFamily == CHIP_FAMILY_ESP32C6 ||
|
|
291
364
|
this.chipFamily == CHIP_FAMILY_ESP32C61 ||
|
|
292
365
|
this.chipFamily == CHIP_FAMILY_ESP32H2 ||
|
|
293
|
-
this.chipFamily ==
|
|
366
|
+
this.chipFamily == CHIP_FAMILY_ESP32H4 ||
|
|
367
|
+
this.chipFamily == CHIP_FAMILY_ESP32H21 ||
|
|
368
|
+
this.chipFamily == CHIP_FAMILY_ESP32P4 ||
|
|
369
|
+
this.chipFamily == CHIP_FAMILY_ESP32S31) {
|
|
294
370
|
macAddr[0] = (mac1 >> 8) & 0xff;
|
|
295
371
|
macAddr[1] = mac1 & 0xff;
|
|
296
372
|
macAddr[2] = (mac0 >> 24) & 0xff;
|
|
@@ -339,7 +415,10 @@ export class ESPLoader extends EventTarget {
|
|
|
339
415
|
CHIP_FAMILY_ESP32C6,
|
|
340
416
|
CHIP_FAMILY_ESP32C61,
|
|
341
417
|
CHIP_FAMILY_ESP32H2,
|
|
418
|
+
CHIP_FAMILY_ESP32H4,
|
|
419
|
+
CHIP_FAMILY_ESP32H21,
|
|
342
420
|
CHIP_FAMILY_ESP32P4,
|
|
421
|
+
CHIP_FAMILY_ESP32S31,
|
|
343
422
|
].includes(this.chipFamily)) {
|
|
344
423
|
statusLen = 4;
|
|
345
424
|
}
|
|
@@ -392,8 +471,6 @@ export class ESPLoader extends EventTarget {
|
|
|
392
471
|
* @name readPacket
|
|
393
472
|
* Generator to read SLIP packets from a serial port.
|
|
394
473
|
* Yields one full SLIP packet at a time, raises exception on timeout or invalid data.
|
|
395
|
-
* Designed to avoid too many calls to serial.read(1), which can bog
|
|
396
|
-
* down on slow systems.
|
|
397
474
|
*/
|
|
398
475
|
async readPacket(timeout) {
|
|
399
476
|
let partialPacket = null;
|
|
@@ -408,7 +485,8 @@ export class ESPLoader extends EventTarget {
|
|
|
408
485
|
break;
|
|
409
486
|
}
|
|
410
487
|
else {
|
|
411
|
-
|
|
488
|
+
// Reduced sleep time for faster response during high-speed transfers
|
|
489
|
+
await sleep(1);
|
|
412
490
|
}
|
|
413
491
|
}
|
|
414
492
|
if (readBytes.length == 0) {
|
|
@@ -509,7 +587,6 @@ export class ESPLoader extends EventTarget {
|
|
|
509
587
|
if (this.chipFamily == CHIP_FAMILY_ESP8266) {
|
|
510
588
|
throw new Error("Changing baud rate is not supported on the ESP8266");
|
|
511
589
|
}
|
|
512
|
-
this.logger.log("Attempting to change baud rate to " + baud + "...");
|
|
513
590
|
try {
|
|
514
591
|
// Send ESP_ROM_BAUD(115200) as the old one if running STUB otherwise 0
|
|
515
592
|
let buffer = pack("<II", baud, this.IS_STUB ? ESP_ROM_BAUD : 0);
|
|
@@ -525,6 +602,21 @@ export class ESPLoader extends EventTarget {
|
|
|
525
602
|
else {
|
|
526
603
|
await this.reconfigurePort(baud);
|
|
527
604
|
}
|
|
605
|
+
// Track current baudrate for reconnect
|
|
606
|
+
if (this._parent) {
|
|
607
|
+
this._parent._currentBaudRate = baud;
|
|
608
|
+
}
|
|
609
|
+
else {
|
|
610
|
+
this._currentBaudRate = baud;
|
|
611
|
+
}
|
|
612
|
+
// Warn if baudrate exceeds USB-Serial chip capability
|
|
613
|
+
const maxBaud = this._parent
|
|
614
|
+
? this._parent._maxUSBSerialBaudrate
|
|
615
|
+
: this._maxUSBSerialBaudrate;
|
|
616
|
+
if (maxBaud && baud > maxBaud) {
|
|
617
|
+
this.logger.log(`⚠️ WARNING: Baudrate ${baud} exceeds USB-Serial chip limit (${maxBaud})!`);
|
|
618
|
+
this.logger.log(`⚠️ This may cause data corruption or connection failures!`);
|
|
619
|
+
}
|
|
528
620
|
this.logger.log(`Changed baud rate to ${baud}`);
|
|
529
621
|
}
|
|
530
622
|
async reconfigurePort(baud) {
|
|
@@ -538,6 +630,8 @@ export class ESPLoader extends EventTarget {
|
|
|
538
630
|
await this.port.close();
|
|
539
631
|
// Reopen Port
|
|
540
632
|
await this.port.open({ baudRate: baud });
|
|
633
|
+
// Clear buffer again
|
|
634
|
+
await this.flushSerialBuffers();
|
|
541
635
|
// Restart Readloop
|
|
542
636
|
this.readLoop();
|
|
543
637
|
}
|
|
@@ -556,10 +650,10 @@ export class ESPLoader extends EventTarget {
|
|
|
556
650
|
this._inputBuffer.length = 0;
|
|
557
651
|
let response = await this._sync();
|
|
558
652
|
if (response) {
|
|
559
|
-
await sleep(
|
|
653
|
+
await sleep(SYNC_TIMEOUT);
|
|
560
654
|
return true;
|
|
561
655
|
}
|
|
562
|
-
await sleep(
|
|
656
|
+
await sleep(SYNC_TIMEOUT);
|
|
563
657
|
}
|
|
564
658
|
throw new Error("Couldn't sync to ESP. Try resetting.");
|
|
565
659
|
}
|
|
@@ -690,6 +784,8 @@ export class ESPLoader extends EventTarget {
|
|
|
690
784
|
* number of blocks requred.
|
|
691
785
|
*/
|
|
692
786
|
async flashBegin(size = 0, offset = 0, encrypted = false) {
|
|
787
|
+
// Flush serial buffers before flash write operation
|
|
788
|
+
await this.flushSerialBuffers();
|
|
693
789
|
let eraseSize;
|
|
694
790
|
let buffer;
|
|
695
791
|
let flashWriteSize = this.getFlashWriteSize();
|
|
@@ -704,7 +800,10 @@ export class ESPLoader extends EventTarget {
|
|
|
704
800
|
CHIP_FAMILY_ESP32C6,
|
|
705
801
|
CHIP_FAMILY_ESP32C61,
|
|
706
802
|
CHIP_FAMILY_ESP32H2,
|
|
803
|
+
CHIP_FAMILY_ESP32H4,
|
|
804
|
+
CHIP_FAMILY_ESP32H21,
|
|
707
805
|
CHIP_FAMILY_ESP32P4,
|
|
806
|
+
CHIP_FAMILY_ESP32S31,
|
|
708
807
|
].includes(this.chipFamily)) {
|
|
709
808
|
await this.checkCommand(ESP_SPI_ATTACH, new Array(8).fill(0));
|
|
710
809
|
}
|
|
@@ -733,7 +832,10 @@ export class ESPLoader extends EventTarget {
|
|
|
733
832
|
this.chipFamily == CHIP_FAMILY_ESP32C6 ||
|
|
734
833
|
this.chipFamily == CHIP_FAMILY_ESP32C61 ||
|
|
735
834
|
this.chipFamily == CHIP_FAMILY_ESP32H2 ||
|
|
736
|
-
this.chipFamily ==
|
|
835
|
+
this.chipFamily == CHIP_FAMILY_ESP32H4 ||
|
|
836
|
+
this.chipFamily == CHIP_FAMILY_ESP32H21 ||
|
|
837
|
+
this.chipFamily == CHIP_FAMILY_ESP32P4 ||
|
|
838
|
+
this.chipFamily == CHIP_FAMILY_ESP32S31) {
|
|
737
839
|
buffer = buffer.concat(pack("<I", encrypted ? 1 : 0));
|
|
738
840
|
}
|
|
739
841
|
this.logger.log("Erase size " +
|
|
@@ -959,8 +1061,13 @@ export class ESPLoader extends EventTarget {
|
|
|
959
1061
|
let data = pack("<II", entrypoint == 0 ? 1 : 0, entrypoint);
|
|
960
1062
|
return await this.checkCommand(ESP_MEM_END, data, 0, timeout);
|
|
961
1063
|
}
|
|
962
|
-
async runStub() {
|
|
1064
|
+
async runStub(skipFlashDetection = false) {
|
|
963
1065
|
const stub = await getStubCode(this.chipFamily, this.chipRevision);
|
|
1066
|
+
// No stub available for this chip, return ROM loader
|
|
1067
|
+
if (stub === null) {
|
|
1068
|
+
this.logger.log(`Stub flasher is not yet supported on ${this.chipName}, using ROM loader`);
|
|
1069
|
+
return this;
|
|
1070
|
+
}
|
|
964
1071
|
// We're transferring over USB, right?
|
|
965
1072
|
let ramBlock = USB_RAM_BLOCK;
|
|
966
1073
|
// Upload
|
|
@@ -981,7 +1088,6 @@ export class ESPLoader extends EventTarget {
|
|
|
981
1088
|
}
|
|
982
1089
|
}
|
|
983
1090
|
}
|
|
984
|
-
this.logger.log("Running stub...");
|
|
985
1091
|
await this.memFinish(stub["entry"]);
|
|
986
1092
|
let pChar;
|
|
987
1093
|
const p = await this.readPacket(500);
|
|
@@ -991,8 +1097,10 @@ export class ESPLoader extends EventTarget {
|
|
|
991
1097
|
}
|
|
992
1098
|
this.logger.log("Stub is now running...");
|
|
993
1099
|
const espStubLoader = new EspStubLoader(this.port, this.logger, this);
|
|
994
|
-
// Try to autodetect the flash size
|
|
995
|
-
|
|
1100
|
+
// Try to autodetect the flash size.
|
|
1101
|
+
if (!skipFlashDetection) {
|
|
1102
|
+
await espStubLoader.detectFlashSize();
|
|
1103
|
+
}
|
|
996
1104
|
return espStubLoader;
|
|
997
1105
|
}
|
|
998
1106
|
async writeToStream(data) {
|
|
@@ -1020,6 +1128,254 @@ export class ESPLoader extends EventTarget {
|
|
|
1020
1128
|
});
|
|
1021
1129
|
this.connected = false;
|
|
1022
1130
|
}
|
|
1131
|
+
/**
|
|
1132
|
+
* @name reconnectAndResume
|
|
1133
|
+
* Reconnect the serial port to flush browser buffers and reload stub
|
|
1134
|
+
*/
|
|
1135
|
+
async reconnect() {
|
|
1136
|
+
if (this._parent) {
|
|
1137
|
+
await this._parent.reconnect();
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
this.logger.log("Reconnecting serial port...");
|
|
1141
|
+
this.connected = false;
|
|
1142
|
+
this.__inputBuffer = [];
|
|
1143
|
+
// Cancel reader
|
|
1144
|
+
if (this._reader) {
|
|
1145
|
+
try {
|
|
1146
|
+
await this._reader.cancel();
|
|
1147
|
+
}
|
|
1148
|
+
catch (err) {
|
|
1149
|
+
this.logger.debug(`Reader cancel error: ${err}`);
|
|
1150
|
+
}
|
|
1151
|
+
this._reader = undefined;
|
|
1152
|
+
}
|
|
1153
|
+
await sleep(SYNC_TIMEOUT);
|
|
1154
|
+
// Close port
|
|
1155
|
+
try {
|
|
1156
|
+
await this.port.close();
|
|
1157
|
+
this.logger.log("Port closed");
|
|
1158
|
+
}
|
|
1159
|
+
catch (err) {
|
|
1160
|
+
this.logger.debug(`Port close error: ${err}`);
|
|
1161
|
+
}
|
|
1162
|
+
// Wait for port to fully close
|
|
1163
|
+
await sleep(SYNC_TIMEOUT);
|
|
1164
|
+
// Open the port
|
|
1165
|
+
this.logger.debug("Opening port...");
|
|
1166
|
+
try {
|
|
1167
|
+
await this.port.open({ baudRate: ESP_ROM_BAUD });
|
|
1168
|
+
this.connected = true;
|
|
1169
|
+
}
|
|
1170
|
+
catch (err) {
|
|
1171
|
+
throw new Error(`Failed to open port: ${err}`);
|
|
1172
|
+
}
|
|
1173
|
+
// Wait for port to be fully ready
|
|
1174
|
+
await sleep(SYNC_TIMEOUT);
|
|
1175
|
+
// Verify port streams are available
|
|
1176
|
+
if (!this.port.readable || !this.port.writable) {
|
|
1177
|
+
throw new Error(`Port streams not available after open (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`);
|
|
1178
|
+
}
|
|
1179
|
+
// Save chip info and flash size (no need to detect again)
|
|
1180
|
+
const savedChipFamily = this.chipFamily;
|
|
1181
|
+
const savedChipName = this.chipName;
|
|
1182
|
+
const savedChipRevision = this.chipRevision;
|
|
1183
|
+
const savedChipVariant = this.chipVariant;
|
|
1184
|
+
const savedFlashSize = this.flashSize;
|
|
1185
|
+
// Reinitialize without chip detection
|
|
1186
|
+
await this.hardReset(true);
|
|
1187
|
+
if (!this._parent) {
|
|
1188
|
+
this.__inputBuffer = [];
|
|
1189
|
+
this.__totalBytesRead = 0;
|
|
1190
|
+
this.readLoop();
|
|
1191
|
+
}
|
|
1192
|
+
await this.flushSerialBuffers();
|
|
1193
|
+
await this.sync();
|
|
1194
|
+
// Restore chip info (skip detection)
|
|
1195
|
+
this.chipFamily = savedChipFamily;
|
|
1196
|
+
this.chipName = savedChipName;
|
|
1197
|
+
this.chipRevision = savedChipRevision;
|
|
1198
|
+
this.chipVariant = savedChipVariant;
|
|
1199
|
+
this.flashSize = savedFlashSize;
|
|
1200
|
+
this.logger.debug(`Reconnect complete (chip: ${this.chipName})`);
|
|
1201
|
+
// Verify port is ready
|
|
1202
|
+
if (!this.port.writable || !this.port.readable) {
|
|
1203
|
+
throw new Error("Port not ready after reconnect");
|
|
1204
|
+
}
|
|
1205
|
+
// Load stub (skip flash detection)
|
|
1206
|
+
const stubLoader = await this.runStub(true);
|
|
1207
|
+
this.logger.debug("Stub loaded");
|
|
1208
|
+
// Restore baudrate if it was changed
|
|
1209
|
+
if (this._currentBaudRate !== ESP_ROM_BAUD) {
|
|
1210
|
+
await stubLoader.setBaudrate(this._currentBaudRate);
|
|
1211
|
+
// Wait for port to be ready after baudrate change
|
|
1212
|
+
await sleep(SYNC_TIMEOUT);
|
|
1213
|
+
// Verify port is still ready after baudrate change
|
|
1214
|
+
if (!this.port.writable || !this.port.readable) {
|
|
1215
|
+
throw new Error(`Port not ready after baudrate change (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
// Copy stub state to this instance if we're a stub loader
|
|
1219
|
+
if (this.IS_STUB) {
|
|
1220
|
+
Object.assign(this, stubLoader);
|
|
1221
|
+
}
|
|
1222
|
+
this.logger.debug("Reconnection successful");
|
|
1223
|
+
}
|
|
1224
|
+
/**
|
|
1225
|
+
* @name flushSerialBuffers
|
|
1226
|
+
* Flush any pending data in the TX and RX serial port buffers
|
|
1227
|
+
* This clears both the application RX buffer and waits for hardware buffers to drain
|
|
1228
|
+
*/
|
|
1229
|
+
async flushSerialBuffers() {
|
|
1230
|
+
// Clear application RX buffer
|
|
1231
|
+
if (!this._parent) {
|
|
1232
|
+
this.__inputBuffer = [];
|
|
1233
|
+
}
|
|
1234
|
+
// Wait for any pending TX operations and in-flight RX data
|
|
1235
|
+
await sleep(SYNC_TIMEOUT);
|
|
1236
|
+
// Clear RX buffer again
|
|
1237
|
+
if (!this._parent) {
|
|
1238
|
+
this.__inputBuffer = [];
|
|
1239
|
+
}
|
|
1240
|
+
// Wait longer to ensure all stale data has been received and discarded
|
|
1241
|
+
await sleep(SYNC_TIMEOUT * 2);
|
|
1242
|
+
// Final clear
|
|
1243
|
+
if (!this._parent) {
|
|
1244
|
+
this.__inputBuffer = [];
|
|
1245
|
+
}
|
|
1246
|
+
this.logger.debug("Serial buffers flushed");
|
|
1247
|
+
}
|
|
1248
|
+
/**
|
|
1249
|
+
* @name readFlash
|
|
1250
|
+
* Read flash memory from the chip (only works with stub loader)
|
|
1251
|
+
* @param addr - Address to read from
|
|
1252
|
+
* @param size - Number of bytes to read
|
|
1253
|
+
* @param onPacketReceived - Optional callback function called when packet is received
|
|
1254
|
+
* @returns Uint8Array containing the flash data
|
|
1255
|
+
*/
|
|
1256
|
+
async readFlash(addr, size, onPacketReceived) {
|
|
1257
|
+
if (!this.IS_STUB) {
|
|
1258
|
+
throw new Error("Reading flash is only supported in stub mode. Please run runStub() first.");
|
|
1259
|
+
}
|
|
1260
|
+
// Check if we should reconnect BEFORE starting the read
|
|
1261
|
+
// Reconnect if total bytes read >= 4MB to ensure clean state
|
|
1262
|
+
if (this._totalBytesRead >= 4 * 1024 * 1024) {
|
|
1263
|
+
this.logger.log(
|
|
1264
|
+
// `Total bytes read: ${this._totalBytesRead}. Reconnecting before new read...`,
|
|
1265
|
+
`Reconnecting before new read...`);
|
|
1266
|
+
try {
|
|
1267
|
+
await this.reconnect();
|
|
1268
|
+
}
|
|
1269
|
+
catch (err) {
|
|
1270
|
+
// If reconnect fails, throw error - don't continue with potentially broken state
|
|
1271
|
+
throw new Error(`Reconnect failed: ${err}`);
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
// Flush serial buffers before flash read operation
|
|
1275
|
+
await this.flushSerialBuffers();
|
|
1276
|
+
this.logger.log(`Reading ${size} bytes from flash at address 0x${addr.toString(16)}...`);
|
|
1277
|
+
const CHUNK_SIZE = 0x10000; // 64KB chunks
|
|
1278
|
+
let allData = new Uint8Array(0);
|
|
1279
|
+
let currentAddr = addr;
|
|
1280
|
+
let remainingSize = size;
|
|
1281
|
+
while (remainingSize > 0) {
|
|
1282
|
+
// Reconnect every 4MB to prevent browser buffer issues
|
|
1283
|
+
if (allData.length > 0 && allData.length % (4 * 1024 * 1024) === 0) {
|
|
1284
|
+
this.logger.debug(`Read ${allData.length} bytes. Reconnecting to clear buffers...`);
|
|
1285
|
+
try {
|
|
1286
|
+
await this.reconnect();
|
|
1287
|
+
}
|
|
1288
|
+
catch (err) {
|
|
1289
|
+
throw new Error(`Reconnect failed during read: ${err}`);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
const chunkSize = Math.min(CHUNK_SIZE, remainingSize);
|
|
1293
|
+
let chunkSuccess = false;
|
|
1294
|
+
let retryCount = 0;
|
|
1295
|
+
const MAX_RETRIES = 3;
|
|
1296
|
+
// Retry loop for this chunk
|
|
1297
|
+
while (!chunkSuccess && retryCount <= MAX_RETRIES) {
|
|
1298
|
+
try {
|
|
1299
|
+
this.logger.debug(`Reading chunk at 0x${currentAddr.toString(16)}, size: 0x${chunkSize.toString(16)}`);
|
|
1300
|
+
// Send read flash command for this chunk
|
|
1301
|
+
let pkt = pack("<IIII", currentAddr, chunkSize, 0x1000, 1024);
|
|
1302
|
+
const [res, _] = await this.checkCommand(ESP_READ_FLASH, pkt);
|
|
1303
|
+
if (res != 0) {
|
|
1304
|
+
throw new Error("Failed to read memory: " + res);
|
|
1305
|
+
}
|
|
1306
|
+
let resp = new Uint8Array(0);
|
|
1307
|
+
while (resp.length < chunkSize) {
|
|
1308
|
+
// Read a SLIP packet
|
|
1309
|
+
let packet;
|
|
1310
|
+
try {
|
|
1311
|
+
packet = await this.readPacket(FLASH_READ_TIMEOUT);
|
|
1312
|
+
}
|
|
1313
|
+
catch (err) {
|
|
1314
|
+
if (err instanceof SlipReadError) {
|
|
1315
|
+
this.logger.debug(`SLIP read error at ${resp.length} bytes: ${err.message}`);
|
|
1316
|
+
// If we've read all the data we need, break
|
|
1317
|
+
if (resp.length >= chunkSize) {
|
|
1318
|
+
break;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
throw err;
|
|
1322
|
+
}
|
|
1323
|
+
if (packet && packet.length > 0) {
|
|
1324
|
+
const packetData = new Uint8Array(packet);
|
|
1325
|
+
// Append to response
|
|
1326
|
+
const newResp = new Uint8Array(resp.length + packetData.length);
|
|
1327
|
+
newResp.set(resp);
|
|
1328
|
+
newResp.set(packetData, resp.length);
|
|
1329
|
+
resp = newResp;
|
|
1330
|
+
// Send acknowledgment
|
|
1331
|
+
const ackData = pack("<I", resp.length);
|
|
1332
|
+
const slipEncodedAck = slipEncode(ackData);
|
|
1333
|
+
await this.writeToStream(slipEncodedAck);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
// Chunk read successfully - append to all data
|
|
1337
|
+
const newAllData = new Uint8Array(allData.length + resp.length);
|
|
1338
|
+
newAllData.set(allData);
|
|
1339
|
+
newAllData.set(resp, allData.length);
|
|
1340
|
+
allData = newAllData;
|
|
1341
|
+
chunkSuccess = true;
|
|
1342
|
+
}
|
|
1343
|
+
catch (err) {
|
|
1344
|
+
retryCount++;
|
|
1345
|
+
// Check if it's a timeout error
|
|
1346
|
+
if (err instanceof SlipReadError &&
|
|
1347
|
+
err.message.includes("Timed out")) {
|
|
1348
|
+
if (retryCount <= MAX_RETRIES) {
|
|
1349
|
+
this.logger.log(`⚠️ Timeout error at 0x${currentAddr.toString(16)}. Reconnecting and retrying (attempt ${retryCount}/${MAX_RETRIES})...`);
|
|
1350
|
+
try {
|
|
1351
|
+
await this.reconnect();
|
|
1352
|
+
// Continue to retry the same chunk
|
|
1353
|
+
}
|
|
1354
|
+
catch (reconnectErr) {
|
|
1355
|
+
throw new Error(`Reconnect failed: ${reconnectErr}`);
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
else {
|
|
1359
|
+
throw new Error(`Failed to read chunk at 0x${currentAddr.toString(16)} after ${MAX_RETRIES} retries: ${err}`);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
else {
|
|
1363
|
+
// Non-timeout error, don't retry
|
|
1364
|
+
throw err;
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
// Update progress (use empty array since we already appended to allData)
|
|
1369
|
+
if (onPacketReceived) {
|
|
1370
|
+
onPacketReceived(new Uint8Array(chunkSize), allData.length, size);
|
|
1371
|
+
}
|
|
1372
|
+
currentAddr += chunkSize;
|
|
1373
|
+
remainingSize -= chunkSize;
|
|
1374
|
+
this.logger.debug(`Total progress: 0x${allData.length.toString(16)}/0x${size.toString(16)} bytes`);
|
|
1375
|
+
}
|
|
1376
|
+
this.logger.debug(`Successfully read ${allData.length} bytes from flash`);
|
|
1377
|
+
return allData;
|
|
1378
|
+
}
|
|
1023
1379
|
}
|
|
1024
1380
|
class EspStubLoader extends ESPLoader {
|
|
1025
1381
|
constructor() {
|
|
@@ -1036,6 +1392,10 @@ class EspStubLoader extends ESPLoader {
|
|
|
1036
1392
|
*/
|
|
1037
1393
|
async memBegin(size, blocks, blocksize, offset) {
|
|
1038
1394
|
let stub = await getStubCode(this.chipFamily, this.chipRevision);
|
|
1395
|
+
// Stub may be null for chips without stub support
|
|
1396
|
+
if (stub === null) {
|
|
1397
|
+
return;
|
|
1398
|
+
}
|
|
1039
1399
|
let load_start = offset;
|
|
1040
1400
|
let load_end = offset + size;
|
|
1041
1401
|
console.log(load_start, load_end);
|
package/dist/index.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ import { Logger } from "./const";
|
|
|
2
2
|
import { ESPLoader } from "./esp_loader";
|
|
3
3
|
export type { Logger } from "./const";
|
|
4
4
|
export { ESPLoader } from "./esp_loader";
|
|
5
|
-
export { CHIP_FAMILY_ESP32, CHIP_FAMILY_ESP32S2, CHIP_FAMILY_ESP32S3, CHIP_FAMILY_ESP8266, CHIP_FAMILY_ESP32C2, CHIP_FAMILY_ESP32C3, CHIP_FAMILY_ESP32C5, CHIP_FAMILY_ESP32C6, CHIP_FAMILY_ESP32C61, CHIP_FAMILY_ESP32H2, CHIP_FAMILY_ESP32P4, } from "./const";
|
|
5
|
+
export { CHIP_FAMILY_ESP32, CHIP_FAMILY_ESP32S2, CHIP_FAMILY_ESP32S3, CHIP_FAMILY_ESP8266, CHIP_FAMILY_ESP32C2, CHIP_FAMILY_ESP32C3, CHIP_FAMILY_ESP32C5, CHIP_FAMILY_ESP32C6, CHIP_FAMILY_ESP32C61, CHIP_FAMILY_ESP32H2, CHIP_FAMILY_ESP32H4, CHIP_FAMILY_ESP32H21, CHIP_FAMILY_ESP32P4, CHIP_FAMILY_ESP32S31, } from "./const";
|
|
6
6
|
export declare const connect: (logger: Logger) => Promise<ESPLoader>;
|
package/dist/index.js
CHANGED
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
import { ESP_ROM_BAUD } from "./const";
|
|
3
3
|
import { ESPLoader } from "./esp_loader";
|
|
4
4
|
export { ESPLoader } from "./esp_loader";
|
|
5
|
-
export { CHIP_FAMILY_ESP32, CHIP_FAMILY_ESP32S2, CHIP_FAMILY_ESP32S3, CHIP_FAMILY_ESP8266, CHIP_FAMILY_ESP32C2, CHIP_FAMILY_ESP32C3, CHIP_FAMILY_ESP32C5, CHIP_FAMILY_ESP32C6, CHIP_FAMILY_ESP32C61, CHIP_FAMILY_ESP32H2, CHIP_FAMILY_ESP32P4, } from "./const";
|
|
5
|
+
export { CHIP_FAMILY_ESP32, CHIP_FAMILY_ESP32S2, CHIP_FAMILY_ESP32S3, CHIP_FAMILY_ESP8266, CHIP_FAMILY_ESP32C2, CHIP_FAMILY_ESP32C3, CHIP_FAMILY_ESP32C5, CHIP_FAMILY_ESP32C6, CHIP_FAMILY_ESP32C61, CHIP_FAMILY_ESP32H2, CHIP_FAMILY_ESP32H4, CHIP_FAMILY_ESP32H21, CHIP_FAMILY_ESP32P4, CHIP_FAMILY_ESP32S31, } from "./const";
|
|
6
6
|
export const connect = async (logger) => {
|
|
7
7
|
// - Request a port and open a connection.
|
|
8
8
|
const port = await navigator.serial.requestPort();
|
|
9
|
-
logger.log("Connecting...");
|
|
10
9
|
await port.open({ baudRate: ESP_ROM_BAUD });
|
|
11
10
|
logger.log("Connected successfully.");
|
|
12
11
|
return new ESPLoader(port, logger);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESP32 Partition Table Parser
|
|
3
|
+
* Based on ESP-IDF partition table format
|
|
4
|
+
*/
|
|
5
|
+
export interface Partition {
|
|
6
|
+
name: string;
|
|
7
|
+
type: number;
|
|
8
|
+
subtype: number;
|
|
9
|
+
offset: number;
|
|
10
|
+
size: number;
|
|
11
|
+
flags: number;
|
|
12
|
+
typeName: string;
|
|
13
|
+
subtypeName: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Parse the entire partition table
|
|
17
|
+
*/
|
|
18
|
+
export declare function parsePartitionTable(data: Uint8Array): Partition[];
|
|
19
|
+
/**
|
|
20
|
+
* Get the default partition table offset
|
|
21
|
+
*/
|
|
22
|
+
export declare function getPartitionTableOffset(): number;
|
|
23
|
+
/**
|
|
24
|
+
* Format size in human-readable format
|
|
25
|
+
*/
|
|
26
|
+
export declare function formatSize(bytes: number): string;
|