tasmota-webserial-esptool 9.1.8 → 9.1.9
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.js +51 -25
- package/dist/index.d.ts +1 -1
- package/dist/index.js +13 -10
- package/dist/web/index.js +1 -1
- package/js/modules/esptool.js +1 -1
- package/js/script.js +8 -1
- package/js/webusb-serial.js +9 -19
- package/package.json +1 -1
- package/src/esp_loader.ts +59 -26
- package/src/index.ts +40 -13
package/dist/esp_loader.js
CHANGED
|
@@ -25,8 +25,7 @@ export class ESPLoader extends EventTarget {
|
|
|
25
25
|
this.__commandLock = Promise.resolve([0, []]);
|
|
26
26
|
this.__isReconfiguring = false;
|
|
27
27
|
this.__abandonCurrentOperation = false;
|
|
28
|
-
// Adaptive speed adjustment for flash read operations
|
|
29
|
-
// Using fixed conservative values that work reliably
|
|
28
|
+
// Adaptive speed adjustment for flash read operations
|
|
30
29
|
this.__adaptiveBlockMultiplier = 1;
|
|
31
30
|
this.__adaptiveMaxInFlightMultiplier = 1;
|
|
32
31
|
this.__consecutiveSuccessfulChunks = 0;
|
|
@@ -37,6 +36,7 @@ export class ESPLoader extends EventTarget {
|
|
|
37
36
|
this.__writeChain = Promise.resolve();
|
|
38
37
|
}
|
|
39
38
|
// Chip properties with parent delegation
|
|
39
|
+
// chipFamily accessed before initialization as designed
|
|
40
40
|
get chipFamily() {
|
|
41
41
|
return this._parent ? this._parent.chipFamily : this.__chipFamily;
|
|
42
42
|
}
|
|
@@ -82,7 +82,13 @@ export class ESPLoader extends EventTarget {
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
get _inputBuffer() {
|
|
85
|
-
|
|
85
|
+
if (this._parent) {
|
|
86
|
+
return this._parent._inputBuffer;
|
|
87
|
+
}
|
|
88
|
+
if (this.__inputBuffer === undefined) {
|
|
89
|
+
throw new Error("_inputBuffer accessed before initialization");
|
|
90
|
+
}
|
|
91
|
+
return this.__inputBuffer;
|
|
86
92
|
}
|
|
87
93
|
get _inputBufferReadIndex() {
|
|
88
94
|
return this._parent
|
|
@@ -756,28 +762,28 @@ export class ESPLoader extends EventTarget {
|
|
|
756
762
|
// Strategy 1: USB-JTAG/Serial (works in CDC mode on Desktop)
|
|
757
763
|
resetStrategies.push({
|
|
758
764
|
name: "USB-JTAG/Serial (WebUSB) - ESP32-S2",
|
|
759
|
-
fn: async
|
|
765
|
+
fn: async () => {
|
|
760
766
|
return await self.hardResetUSBJTAGSerialWebUSB();
|
|
761
767
|
},
|
|
762
768
|
});
|
|
763
769
|
// Strategy 2: USB-JTAG/Serial Inverted DTR (works in JTAG mode)
|
|
764
770
|
resetStrategies.push({
|
|
765
771
|
name: "USB-JTAG/Serial Inverted DTR (WebUSB) - ESP32-S2",
|
|
766
|
-
fn: async
|
|
772
|
+
fn: async () => {
|
|
767
773
|
return await self.hardResetUSBJTAGSerialInvertedDTRWebUSB();
|
|
768
774
|
},
|
|
769
775
|
});
|
|
770
776
|
// Strategy 3: UnixTight (CDC fallback)
|
|
771
777
|
resetStrategies.push({
|
|
772
778
|
name: "UnixTight (WebUSB) - ESP32-S2 CDC",
|
|
773
|
-
fn: async
|
|
779
|
+
fn: async () => {
|
|
774
780
|
return await self.hardResetUnixTightWebUSB();
|
|
775
781
|
},
|
|
776
782
|
});
|
|
777
783
|
// Strategy 4: Classic reset (CDC fallback)
|
|
778
784
|
resetStrategies.push({
|
|
779
785
|
name: "Classic (WebUSB) - ESP32-S2 CDC",
|
|
780
|
-
fn: async
|
|
786
|
+
fn: async () => {
|
|
781
787
|
return await self.hardResetClassicWebUSB();
|
|
782
788
|
},
|
|
783
789
|
});
|
|
@@ -786,19 +792,19 @@ export class ESPLoader extends EventTarget {
|
|
|
786
792
|
// Other USB-JTAG chips: Try Inverted DTR first - works best for ESP32-H2 and other JTAG chips
|
|
787
793
|
resetStrategies.push({
|
|
788
794
|
name: "USB-JTAG/Serial Inverted DTR (WebUSB)",
|
|
789
|
-
fn: async
|
|
795
|
+
fn: async () => {
|
|
790
796
|
return await self.hardResetUSBJTAGSerialInvertedDTRWebUSB();
|
|
791
797
|
},
|
|
792
798
|
});
|
|
793
799
|
resetStrategies.push({
|
|
794
800
|
name: "USB-JTAG/Serial (WebUSB)",
|
|
795
|
-
fn: async
|
|
801
|
+
fn: async () => {
|
|
796
802
|
return await self.hardResetUSBJTAGSerialWebUSB();
|
|
797
803
|
},
|
|
798
804
|
});
|
|
799
805
|
resetStrategies.push({
|
|
800
806
|
name: "Inverted DTR Classic (WebUSB)",
|
|
801
|
-
fn: async
|
|
807
|
+
fn: async () => {
|
|
802
808
|
return await self.hardResetInvertedDTRWebUSB();
|
|
803
809
|
},
|
|
804
810
|
});
|
|
@@ -810,31 +816,31 @@ export class ESPLoader extends EventTarget {
|
|
|
810
816
|
// CH340/CH343: UnixTight works best (like CP2102)
|
|
811
817
|
resetStrategies.push({
|
|
812
818
|
name: "UnixTight (WebUSB) - CH34x",
|
|
813
|
-
fn: async
|
|
819
|
+
fn: async () => {
|
|
814
820
|
return await self.hardResetUnixTightWebUSB();
|
|
815
821
|
},
|
|
816
822
|
});
|
|
817
823
|
resetStrategies.push({
|
|
818
824
|
name: "Classic (WebUSB) - CH34x",
|
|
819
|
-
fn: async
|
|
825
|
+
fn: async () => {
|
|
820
826
|
return await self.hardResetClassicWebUSB();
|
|
821
827
|
},
|
|
822
828
|
});
|
|
823
829
|
resetStrategies.push({
|
|
824
830
|
name: "Inverted Both (WebUSB) - CH34x",
|
|
825
|
-
fn: async
|
|
831
|
+
fn: async () => {
|
|
826
832
|
return await self.hardResetInvertedWebUSB();
|
|
827
833
|
},
|
|
828
834
|
});
|
|
829
835
|
resetStrategies.push({
|
|
830
836
|
name: "Inverted RTS (WebUSB) - CH34x",
|
|
831
|
-
fn: async
|
|
837
|
+
fn: async () => {
|
|
832
838
|
return await self.hardResetInvertedRTSWebUSB();
|
|
833
839
|
},
|
|
834
840
|
});
|
|
835
841
|
resetStrategies.push({
|
|
836
842
|
name: "Inverted DTR (WebUSB) - CH34x",
|
|
837
|
-
fn: async
|
|
843
|
+
fn: async () => {
|
|
838
844
|
return await self.hardResetInvertedDTRWebUSB();
|
|
839
845
|
},
|
|
840
846
|
});
|
|
@@ -844,31 +850,31 @@ export class ESPLoader extends EventTarget {
|
|
|
844
850
|
// Try it first, then fallback to other strategies
|
|
845
851
|
resetStrategies.push({
|
|
846
852
|
name: "UnixTight (WebUSB) - CP2102",
|
|
847
|
-
fn: async
|
|
853
|
+
fn: async () => {
|
|
848
854
|
return await self.hardResetUnixTightWebUSB();
|
|
849
855
|
},
|
|
850
856
|
});
|
|
851
857
|
resetStrategies.push({
|
|
852
858
|
name: "Classic (WebUSB) - CP2102",
|
|
853
|
-
fn: async
|
|
859
|
+
fn: async () => {
|
|
854
860
|
return await self.hardResetClassicWebUSB();
|
|
855
861
|
},
|
|
856
862
|
});
|
|
857
863
|
resetStrategies.push({
|
|
858
864
|
name: "Inverted Both (WebUSB) - CP2102",
|
|
859
|
-
fn: async
|
|
865
|
+
fn: async () => {
|
|
860
866
|
return await self.hardResetInvertedWebUSB();
|
|
861
867
|
},
|
|
862
868
|
});
|
|
863
869
|
resetStrategies.push({
|
|
864
870
|
name: "Inverted RTS (WebUSB) - CP2102",
|
|
865
|
-
fn: async
|
|
871
|
+
fn: async () => {
|
|
866
872
|
return await self.hardResetInvertedRTSWebUSB();
|
|
867
873
|
},
|
|
868
874
|
});
|
|
869
875
|
resetStrategies.push({
|
|
870
876
|
name: "Inverted DTR (WebUSB) - CP2102",
|
|
871
|
-
fn: async
|
|
877
|
+
fn: async () => {
|
|
872
878
|
return await self.hardResetInvertedDTRWebUSB();
|
|
873
879
|
},
|
|
874
880
|
});
|
|
@@ -877,7 +883,7 @@ export class ESPLoader extends EventTarget {
|
|
|
877
883
|
// For other USB-Serial chips, try UnixTight first, then multiple strategies
|
|
878
884
|
resetStrategies.push({
|
|
879
885
|
name: "UnixTight (WebUSB)",
|
|
880
|
-
fn: async
|
|
886
|
+
fn: async () => {
|
|
881
887
|
return await self.hardResetUnixTightWebUSB();
|
|
882
888
|
},
|
|
883
889
|
});
|
|
@@ -951,7 +957,6 @@ export class ESPLoader extends EventTarget {
|
|
|
951
957
|
}
|
|
952
958
|
}
|
|
953
959
|
else {
|
|
954
|
-
// Web Serial (Desktop) strategies
|
|
955
960
|
// Strategy: USB-JTAG/Serial reset
|
|
956
961
|
if (isUSBJTAGSerial || isEspressifUSB) {
|
|
957
962
|
resetStrategies.push({
|
|
@@ -1046,9 +1051,9 @@ export class ESPLoader extends EventTarget {
|
|
|
1046
1051
|
// just reset (no bootloader mode)
|
|
1047
1052
|
if (this.isWebUSB()) {
|
|
1048
1053
|
// WebUSB: Use longer delays for better compatibility
|
|
1049
|
-
await this.
|
|
1054
|
+
await this.setRTSWebUSB(true); // EN->LOW
|
|
1050
1055
|
await this.sleep(200);
|
|
1051
|
-
await this.
|
|
1056
|
+
await this.setRTSWebUSB(false);
|
|
1052
1057
|
await this.sleep(200);
|
|
1053
1058
|
this.logger.log("Hard reset (WebUSB).");
|
|
1054
1059
|
}
|
|
@@ -2171,7 +2176,15 @@ export class ESPLoader extends EventTarget {
|
|
|
2171
2176
|
resolve(undefined);
|
|
2172
2177
|
return;
|
|
2173
2178
|
}
|
|
2174
|
-
|
|
2179
|
+
// Set a timeout to prevent hanging (important for node-usb)
|
|
2180
|
+
const timeout = setTimeout(() => {
|
|
2181
|
+
this.logger.debug("Disconnect timeout - forcing resolution");
|
|
2182
|
+
resolve(undefined);
|
|
2183
|
+
}, 1000);
|
|
2184
|
+
this.addEventListener("disconnect", () => {
|
|
2185
|
+
clearTimeout(timeout);
|
|
2186
|
+
resolve(undefined);
|
|
2187
|
+
}, { once: true });
|
|
2175
2188
|
// Only cancel if reader is still active
|
|
2176
2189
|
try {
|
|
2177
2190
|
this._reader.cancel();
|
|
@@ -2179,10 +2192,19 @@ export class ESPLoader extends EventTarget {
|
|
|
2179
2192
|
catch (err) {
|
|
2180
2193
|
this.logger.debug(`Reader cancel error: ${err}`);
|
|
2181
2194
|
// Reader already released, resolve immediately
|
|
2195
|
+
clearTimeout(timeout);
|
|
2182
2196
|
resolve(undefined);
|
|
2183
2197
|
}
|
|
2184
2198
|
});
|
|
2185
2199
|
this.connected = false;
|
|
2200
|
+
// Close the port (important for node-usb adapter)
|
|
2201
|
+
try {
|
|
2202
|
+
await this.port.close();
|
|
2203
|
+
this.logger.debug("Port closed successfully");
|
|
2204
|
+
}
|
|
2205
|
+
catch (err) {
|
|
2206
|
+
this.logger.debug(`Port close error: ${err}`);
|
|
2207
|
+
}
|
|
2186
2208
|
}
|
|
2187
2209
|
/**
|
|
2188
2210
|
* @name reconnectAndResume
|
|
@@ -2701,6 +2723,10 @@ class EspStubLoader extends ESPLoader {
|
|
|
2701
2723
|
if (size > maxValue) {
|
|
2702
2724
|
throw new Error(`Size ${size} exceeds maximum value ${maxValue}`);
|
|
2703
2725
|
}
|
|
2726
|
+
// Check for wrap-around
|
|
2727
|
+
if (offset + size > maxValue) {
|
|
2728
|
+
throw new Error(`Region end (offset + size = ${offset + size}) exceeds maximum addressable range ${maxValue}`);
|
|
2729
|
+
}
|
|
2704
2730
|
const timeout = timeoutPerMb(ERASE_REGION_TIMEOUT_PER_MB, size);
|
|
2705
2731
|
const buffer = pack("<II", offset, size);
|
|
2706
2732
|
await this.checkCommand(ESP_ERASE_REGION, buffer, 0, timeout);
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,6 @@ 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_ESP32H4, CHIP_FAMILY_ESP32H21, CHIP_FAMILY_ESP32P4, CHIP_FAMILY_ESP32S31, } 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, ESP_FLASH_BEGIN, ESP_FLASH_DATA, ESP_FLASH_END, ESP_MEM_BEGIN, ESP_MEM_END, ESP_MEM_DATA, ESP_SYNC, ESP_WRITE_REG, ESP_READ_REG, ESP_ERASE_FLASH, ESP_ERASE_REGION, ESP_READ_FLASH, ESP_SPI_SET_PARAMS, ESP_SPI_ATTACH, ESP_CHANGE_BAUDRATE, ESP_SPI_FLASH_MD5, ESP_GET_SECURITY_INFO, ESP_CHECKSUM_MAGIC, ESP_FLASH_DEFL_BEGIN, ESP_FLASH_DEFL_DATA, ESP_FLASH_DEFL_END, ROM_INVALID_RECV_MSG, USB_RAM_BLOCK, ESP_RAM_BLOCK, DEFAULT_TIMEOUT, CHIP_ERASE_TIMEOUT, MAX_TIMEOUT, SYNC_TIMEOUT, ERASE_REGION_TIMEOUT_PER_MB, MEM_END_ROM_TIMEOUT, FLASH_READ_TIMEOUT, } from "./const";
|
|
6
6
|
export declare const connect: (logger: Logger) => Promise<ESPLoader>;
|
|
7
7
|
export declare const connectWithPort: (port: SerialPort, logger: Logger) => Promise<ESPLoader>;
|
package/dist/index.js
CHANGED
|
@@ -2,30 +2,34 @@
|
|
|
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_ESP32H4, CHIP_FAMILY_ESP32H21, CHIP_FAMILY_ESP32P4, CHIP_FAMILY_ESP32S31,
|
|
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,
|
|
6
|
+
// Command constants
|
|
7
|
+
ESP_FLASH_BEGIN, ESP_FLASH_DATA, ESP_FLASH_END, ESP_MEM_BEGIN, ESP_MEM_END, ESP_MEM_DATA, ESP_SYNC, ESP_WRITE_REG, ESP_READ_REG, ESP_ERASE_FLASH, ESP_ERASE_REGION, ESP_READ_FLASH, ESP_SPI_SET_PARAMS, ESP_SPI_ATTACH, ESP_CHANGE_BAUDRATE, ESP_SPI_FLASH_MD5, ESP_GET_SECURITY_INFO, ESP_CHECKSUM_MAGIC, ESP_FLASH_DEFL_BEGIN, ESP_FLASH_DEFL_DATA, ESP_FLASH_DEFL_END, ROM_INVALID_RECV_MSG,
|
|
8
|
+
// Block size constants
|
|
9
|
+
USB_RAM_BLOCK, ESP_RAM_BLOCK,
|
|
10
|
+
// Timeout constants
|
|
11
|
+
DEFAULT_TIMEOUT, CHIP_ERASE_TIMEOUT, MAX_TIMEOUT, SYNC_TIMEOUT, ERASE_REGION_TIMEOUT_PER_MB, MEM_END_ROM_TIMEOUT, FLASH_READ_TIMEOUT, } from "./const";
|
|
6
12
|
export const connect = async (logger) => {
|
|
13
|
+
// - Request a port and open a connection.
|
|
14
|
+
// Try to use requestSerialPort if available (supports WebUSB for Android)
|
|
7
15
|
let port;
|
|
8
|
-
// Check if a custom requestSerialPort function is available (e.g., from WebUSB wrapper)
|
|
9
16
|
const customRequestPort = globalThis.requestSerialPort;
|
|
10
17
|
if (typeof customRequestPort === "function") {
|
|
11
|
-
// Use custom port request function (handles Android/WebUSB automatically)
|
|
12
|
-
logger.log("Using custom port request function");
|
|
13
18
|
port = await customRequestPort();
|
|
14
19
|
}
|
|
15
20
|
else {
|
|
16
|
-
//
|
|
21
|
+
// Check if Web Serial API is available
|
|
17
22
|
if (!navigator.serial) {
|
|
18
23
|
throw new Error("Web Serial API is not supported in this browser. " +
|
|
19
|
-
"Please use Chrome
|
|
24
|
+
"Please use Chrome, Edge, or Opera on desktop, or Chrome on Android. " +
|
|
20
25
|
"Note: The page must be served over HTTPS or localhost.");
|
|
21
26
|
}
|
|
22
27
|
port = await navigator.serial.requestPort();
|
|
23
28
|
}
|
|
24
|
-
// Only open if not already open (
|
|
29
|
+
// Only open if not already open (requestSerialPort may return an opened port)
|
|
25
30
|
if (!port.readable || !port.writable) {
|
|
26
31
|
await port.open({ baudRate: ESP_ROM_BAUD });
|
|
27
32
|
}
|
|
28
|
-
logger.log("Connected successfully.");
|
|
29
33
|
return new ESPLoader(port, logger);
|
|
30
34
|
};
|
|
31
35
|
export const connectWithPort = async (port, logger) => {
|
|
@@ -33,10 +37,9 @@ export const connectWithPort = async (port, logger) => {
|
|
|
33
37
|
if (!port) {
|
|
34
38
|
throw new Error("Port is required");
|
|
35
39
|
}
|
|
36
|
-
//
|
|
40
|
+
// Check if port is already open, if not open it
|
|
37
41
|
if (!port.readable || !port.writable) {
|
|
38
42
|
await port.open({ baudRate: ESP_ROM_BAUD });
|
|
39
43
|
}
|
|
40
|
-
logger.log("Connected successfully.");
|
|
41
44
|
return new ESPLoader(port, logger);
|
|
42
45
|
};
|