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