tasmota-webserial-esptool 9.1.4 → 9.1.6
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/dist/esp_loader.d.ts +23 -6
- package/dist/esp_loader.js +139 -46
- package/dist/web/index.js +1 -1
- package/js/modules/esptool.js +1 -1
- package/js/webusb-serial.js +7 -10
- package/package.json +1 -1
- package/src/esp_loader.ts +156 -46
package/dist/esp_loader.d.ts
CHANGED
|
@@ -3,10 +3,10 @@ export declare class ESPLoader extends EventTarget {
|
|
|
3
3
|
port: SerialPort;
|
|
4
4
|
logger: Logger;
|
|
5
5
|
private _parent?;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
__chipFamily?: ChipFamily;
|
|
7
|
+
__chipName: string | null;
|
|
8
|
+
__chipRevision: number | null;
|
|
9
|
+
__chipVariant: string | null;
|
|
10
10
|
_efuses: any[];
|
|
11
11
|
_flashsize: number;
|
|
12
12
|
debug: boolean;
|
|
@@ -30,6 +30,14 @@ export declare class ESPLoader extends EventTarget {
|
|
|
30
30
|
private __lastAdaptiveAdjustment;
|
|
31
31
|
private __isCDCDevice;
|
|
32
32
|
constructor(port: SerialPort, logger: Logger, _parent?: ESPLoader | undefined);
|
|
33
|
+
get chipFamily(): ChipFamily;
|
|
34
|
+
set chipFamily(value: ChipFamily);
|
|
35
|
+
get chipName(): string | null;
|
|
36
|
+
set chipName(value: string | null);
|
|
37
|
+
get chipRevision(): number | null;
|
|
38
|
+
set chipRevision(value: number | null);
|
|
39
|
+
get chipVariant(): string | null;
|
|
40
|
+
set chipVariant(value: string | null);
|
|
33
41
|
private get _inputBuffer();
|
|
34
42
|
private get _inputBufferReadIndex();
|
|
35
43
|
private set _inputBufferReadIndex(value);
|
|
@@ -75,6 +83,10 @@ export declare class ESPLoader extends EventTarget {
|
|
|
75
83
|
chipId: number;
|
|
76
84
|
apiVersion: number;
|
|
77
85
|
}>;
|
|
86
|
+
/**
|
|
87
|
+
* Get MAC address from efuses
|
|
88
|
+
*/
|
|
89
|
+
getMacAddress(): Promise<string>;
|
|
78
90
|
/**
|
|
79
91
|
* @name readLoop
|
|
80
92
|
* Reads data from the input stream and places it in the inputBuffer
|
|
@@ -333,9 +345,14 @@ declare class EspStubLoader extends ESPLoader {
|
|
|
333
345
|
*/
|
|
334
346
|
memBegin(size: number, _blocks: number, _blocksize: number, offset: number): Promise<[number, number[]]>;
|
|
335
347
|
/**
|
|
336
|
-
* @name
|
|
337
|
-
*
|
|
348
|
+
* @name eraseFlash
|
|
349
|
+
* Erase entire flash chip
|
|
338
350
|
*/
|
|
339
351
|
eraseFlash(): Promise<void>;
|
|
352
|
+
/**
|
|
353
|
+
* @name eraseRegion
|
|
354
|
+
* Erase a specific region of flash
|
|
355
|
+
*/
|
|
356
|
+
eraseRegion(offset: number, size: number): Promise<void>;
|
|
340
357
|
}
|
|
341
358
|
export {};
|
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_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";
|
|
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_ERASE_REGION, 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
|
import { deflate } from "pako";
|
|
@@ -10,9 +10,9 @@ export class ESPLoader extends EventTarget {
|
|
|
10
10
|
this.port = port;
|
|
11
11
|
this.logger = logger;
|
|
12
12
|
this._parent = _parent;
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
13
|
+
this.__chipName = null;
|
|
14
|
+
this.__chipRevision = null;
|
|
15
|
+
this.__chipVariant = null;
|
|
16
16
|
this._efuses = new Array(4).fill(0);
|
|
17
17
|
this._flashsize = 4 * 1024 * 1024;
|
|
18
18
|
this.debug = false;
|
|
@@ -35,6 +35,51 @@ export class ESPLoader extends EventTarget {
|
|
|
35
35
|
this.state_DTR = false;
|
|
36
36
|
this.__writeChain = Promise.resolve();
|
|
37
37
|
}
|
|
38
|
+
// Chip properties with parent delegation
|
|
39
|
+
get chipFamily() {
|
|
40
|
+
return this._parent ? this._parent.chipFamily : this.__chipFamily;
|
|
41
|
+
}
|
|
42
|
+
set chipFamily(value) {
|
|
43
|
+
if (this._parent) {
|
|
44
|
+
this._parent.chipFamily = value;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
this.__chipFamily = value;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
get chipName() {
|
|
51
|
+
return this._parent ? this._parent.chipName : this.__chipName;
|
|
52
|
+
}
|
|
53
|
+
set chipName(value) {
|
|
54
|
+
if (this._parent) {
|
|
55
|
+
this._parent.chipName = value;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
this.__chipName = value;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
get chipRevision() {
|
|
62
|
+
return this._parent ? this._parent.chipRevision : this.__chipRevision;
|
|
63
|
+
}
|
|
64
|
+
set chipRevision(value) {
|
|
65
|
+
if (this._parent) {
|
|
66
|
+
this._parent.chipRevision = value;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
this.__chipRevision = value;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
get chipVariant() {
|
|
73
|
+
return this._parent ? this._parent.chipVariant : this.__chipVariant;
|
|
74
|
+
}
|
|
75
|
+
set chipVariant(value) {
|
|
76
|
+
if (this._parent) {
|
|
77
|
+
this._parent.chipVariant = value;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.__chipVariant = value;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
38
83
|
get _inputBuffer() {
|
|
39
84
|
return this._parent ? this._parent._inputBuffer : this.__inputBuffer;
|
|
40
85
|
}
|
|
@@ -390,6 +435,18 @@ export class ESPLoader extends EventTarget {
|
|
|
390
435
|
apiVersion,
|
|
391
436
|
};
|
|
392
437
|
}
|
|
438
|
+
/**
|
|
439
|
+
* Get MAC address from efuses
|
|
440
|
+
*/
|
|
441
|
+
async getMacAddress() {
|
|
442
|
+
if (!this._initializationSucceeded) {
|
|
443
|
+
throw new Error("getMacAddress() requires initialize() to have completed successfully");
|
|
444
|
+
}
|
|
445
|
+
const macBytes = this.macAddr(); // chip-family-aware
|
|
446
|
+
return macBytes
|
|
447
|
+
.map((b) => b.toString(16).padStart(2, "0").toUpperCase())
|
|
448
|
+
.join(":");
|
|
449
|
+
}
|
|
393
450
|
/**
|
|
394
451
|
* @name readLoop
|
|
395
452
|
* Reads data from the input stream and places it in the inputBuffer
|
|
@@ -422,6 +479,12 @@ export class ESPLoader extends EventTarget {
|
|
|
422
479
|
catch {
|
|
423
480
|
this.logger.error("Read loop got disconnected");
|
|
424
481
|
}
|
|
482
|
+
finally {
|
|
483
|
+
// Always reset reconfiguring flag when read loop ends
|
|
484
|
+
// This prevents "Cannot write during port reconfiguration" errors
|
|
485
|
+
// when the read loop dies unexpectedly
|
|
486
|
+
this._isReconfiguring = false;
|
|
487
|
+
}
|
|
425
488
|
// Disconnected!
|
|
426
489
|
this.connected = false;
|
|
427
490
|
// Check if this is ESP32-S2 Native USB that needs port reselection
|
|
@@ -2064,52 +2127,45 @@ export class ESPLoader extends EventTarget {
|
|
|
2064
2127
|
this.logger.debug("Port already closed, skipping disconnect");
|
|
2065
2128
|
return;
|
|
2066
2129
|
}
|
|
2130
|
+
// Wait for pending writes to complete
|
|
2067
2131
|
try {
|
|
2068
|
-
|
|
2132
|
+
await this._writeChain;
|
|
2133
|
+
}
|
|
2134
|
+
catch (err) {
|
|
2135
|
+
this.logger.debug(`Pending write error during disconnect: ${err}`);
|
|
2136
|
+
}
|
|
2137
|
+
// Release persistent writer before closing
|
|
2138
|
+
if (this._writer) {
|
|
2069
2139
|
try {
|
|
2070
|
-
await this.
|
|
2140
|
+
await this._writer.close();
|
|
2141
|
+
this._writer.releaseLock();
|
|
2071
2142
|
}
|
|
2072
2143
|
catch (err) {
|
|
2073
|
-
this.logger.debug(`
|
|
2144
|
+
this.logger.debug(`Writer close/release error: ${err}`);
|
|
2074
2145
|
}
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
this.logger.debug(`Writer close/release error: ${err}`);
|
|
2085
|
-
}
|
|
2086
|
-
this._writer = undefined;
|
|
2146
|
+
this._writer = undefined;
|
|
2147
|
+
}
|
|
2148
|
+
else {
|
|
2149
|
+
// No persistent writer exists, close stream directly
|
|
2150
|
+
// This path is taken when no writes have been queued
|
|
2151
|
+
try {
|
|
2152
|
+
const writer = this.port.writable.getWriter();
|
|
2153
|
+
await writer.close();
|
|
2154
|
+
writer.releaseLock();
|
|
2087
2155
|
}
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
// This path is taken when no writes have been queued
|
|
2091
|
-
try {
|
|
2092
|
-
const writer = this.port.writable.getWriter();
|
|
2093
|
-
await writer.close();
|
|
2094
|
-
writer.releaseLock();
|
|
2095
|
-
}
|
|
2096
|
-
catch (err) {
|
|
2097
|
-
this.logger.debug(`Direct writer close error: ${err}`);
|
|
2098
|
-
}
|
|
2156
|
+
catch (err) {
|
|
2157
|
+
this.logger.debug(`Direct writer close error: ${err}`);
|
|
2099
2158
|
}
|
|
2100
|
-
await new Promise((resolve) => {
|
|
2101
|
-
if (!this._reader) {
|
|
2102
|
-
resolve(undefined);
|
|
2103
|
-
return;
|
|
2104
|
-
}
|
|
2105
|
-
this.addEventListener("disconnect", resolve, { once: true });
|
|
2106
|
-
this._reader.cancel();
|
|
2107
|
-
});
|
|
2108
|
-
this.connected = false;
|
|
2109
|
-
}
|
|
2110
|
-
finally {
|
|
2111
|
-
this._isReconfiguring = false;
|
|
2112
2159
|
}
|
|
2160
|
+
await new Promise((resolve) => {
|
|
2161
|
+
if (!this._reader) {
|
|
2162
|
+
resolve(undefined);
|
|
2163
|
+
return;
|
|
2164
|
+
}
|
|
2165
|
+
this.addEventListener("disconnect", resolve, { once: true });
|
|
2166
|
+
this._reader.cancel();
|
|
2167
|
+
});
|
|
2168
|
+
this.connected = false;
|
|
2113
2169
|
}
|
|
2114
2170
|
/**
|
|
2115
2171
|
* @name reconnectAndResume
|
|
@@ -2412,8 +2468,9 @@ export class ESPLoader extends EventTarget {
|
|
|
2412
2468
|
newResp.set(resp);
|
|
2413
2469
|
newResp.set(packetData, resp.length);
|
|
2414
2470
|
resp = newResp;
|
|
2415
|
-
// Send acknowledgment
|
|
2416
|
-
//
|
|
2471
|
+
// Send acknowledgment when we've received maxInFlight bytes
|
|
2472
|
+
// The stub sends packets until (num_sent - num_acked) >= max_in_flight
|
|
2473
|
+
// We MUST wait for all packets before sending ACK
|
|
2417
2474
|
const shouldAck = resp.length >= chunkSize || // End of chunk
|
|
2418
2475
|
resp.length >= lastAckedLength + maxInFlight; // Received all packets
|
|
2419
2476
|
if (shouldAck) {
|
|
@@ -2589,10 +2646,46 @@ class EspStubLoader extends ESPLoader {
|
|
|
2589
2646
|
return [0, []];
|
|
2590
2647
|
}
|
|
2591
2648
|
/**
|
|
2592
|
-
* @name
|
|
2593
|
-
*
|
|
2649
|
+
* @name eraseFlash
|
|
2650
|
+
* Erase entire flash chip
|
|
2594
2651
|
*/
|
|
2595
2652
|
async eraseFlash() {
|
|
2596
2653
|
await this.checkCommand(ESP_ERASE_FLASH, [], 0, CHIP_ERASE_TIMEOUT);
|
|
2597
2654
|
}
|
|
2655
|
+
/**
|
|
2656
|
+
* @name eraseRegion
|
|
2657
|
+
* Erase a specific region of flash
|
|
2658
|
+
*/
|
|
2659
|
+
async eraseRegion(offset, size) {
|
|
2660
|
+
// Validate inputs
|
|
2661
|
+
if (offset < 0) {
|
|
2662
|
+
throw new Error(`Invalid offset: ${offset} (must be non-negative)`);
|
|
2663
|
+
}
|
|
2664
|
+
if (size < 0) {
|
|
2665
|
+
throw new Error(`Invalid size: ${size} (must be non-negative)`);
|
|
2666
|
+
}
|
|
2667
|
+
// No-op for zero size
|
|
2668
|
+
if (size === 0) {
|
|
2669
|
+
this.logger.log("eraseRegion: size is 0, skipping erase");
|
|
2670
|
+
return;
|
|
2671
|
+
}
|
|
2672
|
+
// Check for sector alignment
|
|
2673
|
+
if (offset % FLASH_SECTOR_SIZE !== 0) {
|
|
2674
|
+
throw new Error(`Offset ${offset} (0x${offset.toString(16)}) is not aligned to flash sector size ${FLASH_SECTOR_SIZE} (0x${FLASH_SECTOR_SIZE.toString(16)})`);
|
|
2675
|
+
}
|
|
2676
|
+
if (size % FLASH_SECTOR_SIZE !== 0) {
|
|
2677
|
+
throw new Error(`Size ${size} (0x${size.toString(16)}) is not aligned to flash sector size ${FLASH_SECTOR_SIZE} (0x${FLASH_SECTOR_SIZE.toString(16)})`);
|
|
2678
|
+
}
|
|
2679
|
+
// Check for reasonable bounds (prevent wrapping in pack)
|
|
2680
|
+
const maxValue = 0xffffffff; // 32-bit unsigned max
|
|
2681
|
+
if (offset > maxValue) {
|
|
2682
|
+
throw new Error(`Offset ${offset} exceeds maximum value ${maxValue}`);
|
|
2683
|
+
}
|
|
2684
|
+
if (size > maxValue) {
|
|
2685
|
+
throw new Error(`Size ${size} exceeds maximum value ${maxValue}`);
|
|
2686
|
+
}
|
|
2687
|
+
const timeout = timeoutPerMb(ERASE_REGION_TIMEOUT_PER_MB, size);
|
|
2688
|
+
const buffer = pack("<II", offset, size);
|
|
2689
|
+
await this.checkCommand(ESP_ERASE_REGION, buffer, 0, timeout);
|
|
2690
|
+
}
|
|
2598
2691
|
}
|