tasmota-webserial-esptool 7.3.0 → 7.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esp_loader.d.ts +13 -0
- package/dist/esp_loader.js +305 -138
- package/dist/stubs/esp32c3.json +3 -3
- package/dist/stubs/esp32c5.json +3 -3
- package/dist/stubs/esp32c6.json +3 -3
- package/dist/stubs/esp32c61.json +3 -3
- package/dist/stubs/esp32h2.json +3 -3
- package/dist/stubs/esp32p4.json +3 -3
- package/dist/stubs/esp32p4r3.json +3 -3
- package/dist/stubs/esp32s3.json +3 -3
- package/dist/web/esp32c3-CHKfoI8W.js +1 -0
- package/dist/web/esp32c5-BDW4KtLo.js +1 -0
- package/dist/web/esp32c6-il8tTxAG.js +1 -0
- package/dist/web/esp32c61-thKzxBGf.js +1 -0
- package/dist/web/esp32h2-CxoUHv_P.js +1 -0
- package/dist/web/esp32p4-D3jLP-jY.js +1 -0
- package/dist/web/esp32p4r3-CqI71ojR.js +1 -0
- package/dist/web/esp32s3-DGwDVIgz.js +1 -0
- package/dist/web/index.js +1 -1
- package/js/modules/esp32c3-CHKfoI8W.js +1 -0
- package/js/modules/esp32c5-BDW4KtLo.js +1 -0
- package/js/modules/esp32c6-il8tTxAG.js +1 -0
- package/js/modules/esp32c61-thKzxBGf.js +1 -0
- package/js/modules/esp32h2-CxoUHv_P.js +1 -0
- package/js/modules/esp32p4-D3jLP-jY.js +1 -0
- package/js/modules/esp32p4r3-CqI71ojR.js +1 -0
- package/js/modules/esp32s3-DGwDVIgz.js +1 -0
- package/js/modules/esptool.js +1 -1
- package/package.json +1 -1
- package/src/esp_loader.ts +326 -143
- package/src/stubs/README.md +1 -1
- package/src/stubs/esp32c3.json +3 -3
- package/src/stubs/esp32c5.json +3 -3
- package/src/stubs/esp32c6.json +3 -3
- package/src/stubs/esp32c61.json +3 -3
- package/src/stubs/esp32h2.json +3 -3
- package/src/stubs/esp32p4.json +3 -3
- package/src/stubs/esp32p4r3.json +3 -3
- package/src/stubs/esp32s3.json +3 -3
- package/dist/web/esp32c3-BGQu6Tl5.js +0 -1
- package/dist/web/esp32c5-0b050IXn.js +0 -1
- package/dist/web/esp32c6-D9SxtU9b.js +0 -1
- package/dist/web/esp32c61-B2dSOrao.js +0 -1
- package/dist/web/esp32h2-BBdaXb2C.js +0 -1
- package/dist/web/esp32p4-BLGlFHot.js +0 -1
- package/dist/web/esp32p4r3-CEI3EOJv.js +0 -1
- package/dist/web/esp32s3-BUw3lf0r.js +0 -1
- package/js/modules/esp32c3-BGQu6Tl5.js +0 -1
- package/js/modules/esp32c5-0b050IXn.js +0 -1
- package/js/modules/esp32c6-D9SxtU9b.js +0 -1
- package/js/modules/esp32c61-B2dSOrao.js +0 -1
- package/js/modules/esp32h2-BBdaXb2C.js +0 -1
- package/js/modules/esp32p4-BLGlFHot.js +0 -1
- package/js/modules/esp32p4r3-CEI3EOJv.js +0 -1
- package/js/modules/esp32s3-BUw3lf0r.js +0 -1
package/src/esp_loader.ts
CHANGED
|
@@ -85,6 +85,8 @@ export class ESPLoader extends EventTarget {
|
|
|
85
85
|
private _reader?: ReadableStreamDefaultReader<Uint8Array>;
|
|
86
86
|
private _isESP32S2NativeUSB: boolean = false;
|
|
87
87
|
private _initializationSucceeded: boolean = false;
|
|
88
|
+
private __commandLock: Promise<[number, number[]]> = Promise.resolve([0, []]);
|
|
89
|
+
private _isReconfiguring: boolean = false;
|
|
88
90
|
|
|
89
91
|
constructor(
|
|
90
92
|
public port: SerialPort,
|
|
@@ -112,6 +114,18 @@ export class ESPLoader extends EventTarget {
|
|
|
112
114
|
}
|
|
113
115
|
}
|
|
114
116
|
|
|
117
|
+
private get _commandLock(): Promise<[number, number[]]> {
|
|
118
|
+
return this._parent ? this._parent._commandLock : this.__commandLock;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private set _commandLock(value: Promise<[number, number[]]>) {
|
|
122
|
+
if (this._parent) {
|
|
123
|
+
this._parent._commandLock = value;
|
|
124
|
+
} else {
|
|
125
|
+
this.__commandLock = value;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
115
129
|
private detectUSBSerialChip(
|
|
116
130
|
vendorId: number,
|
|
117
131
|
productId: number,
|
|
@@ -549,6 +563,9 @@ export class ESPLoader extends EventTarget {
|
|
|
549
563
|
* Send a command packet, check that the command succeeded and
|
|
550
564
|
* return a tuple with the value and data.
|
|
551
565
|
* See the ESP Serial Protocol for more details on what value/data are
|
|
566
|
+
*
|
|
567
|
+
* Commands are serialized to prevent concurrent execution which can cause
|
|
568
|
+
* WritableStream lock contention on CP210x adapters under Windows
|
|
552
569
|
*/
|
|
553
570
|
async checkCommand(
|
|
554
571
|
opcode: number,
|
|
@@ -556,69 +573,77 @@ export class ESPLoader extends EventTarget {
|
|
|
556
573
|
checksum = 0,
|
|
557
574
|
timeout = DEFAULT_TIMEOUT,
|
|
558
575
|
): Promise<[number, number[]]> {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
let statusLen = 0;
|
|
576
|
+
// Serialize command execution to prevent lock contention
|
|
577
|
+
const executeCommand = async (): Promise<[number, number[]]> => {
|
|
578
|
+
timeout = Math.min(timeout, MAX_TIMEOUT);
|
|
579
|
+
await this.sendCommand(opcode, buffer, checksum);
|
|
580
|
+
const [value, responseData] = await this.getResponse(opcode, timeout);
|
|
581
|
+
|
|
582
|
+
if (responseData === null) {
|
|
583
|
+
throw new Error("Didn't get enough status bytes");
|
|
584
|
+
}
|
|
569
585
|
|
|
570
|
-
|
|
571
|
-
statusLen =
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
// assume modern chips use 4-byte status
|
|
593
|
-
if (opcode === ESP_GET_SECURITY_INFO) {
|
|
586
|
+
let data = responseData;
|
|
587
|
+
let statusLen = 0;
|
|
588
|
+
|
|
589
|
+
if (this.IS_STUB || this.chipFamily == CHIP_FAMILY_ESP8266) {
|
|
590
|
+
statusLen = 2;
|
|
591
|
+
} else if (
|
|
592
|
+
[
|
|
593
|
+
CHIP_FAMILY_ESP32,
|
|
594
|
+
CHIP_FAMILY_ESP32S2,
|
|
595
|
+
CHIP_FAMILY_ESP32S3,
|
|
596
|
+
CHIP_FAMILY_ESP32C2,
|
|
597
|
+
CHIP_FAMILY_ESP32C3,
|
|
598
|
+
CHIP_FAMILY_ESP32C5,
|
|
599
|
+
CHIP_FAMILY_ESP32C6,
|
|
600
|
+
CHIP_FAMILY_ESP32C61,
|
|
601
|
+
CHIP_FAMILY_ESP32H2,
|
|
602
|
+
CHIP_FAMILY_ESP32H4,
|
|
603
|
+
CHIP_FAMILY_ESP32H21,
|
|
604
|
+
CHIP_FAMILY_ESP32P4,
|
|
605
|
+
CHIP_FAMILY_ESP32S31,
|
|
606
|
+
].includes(this.chipFamily)
|
|
607
|
+
) {
|
|
594
608
|
statusLen = 4;
|
|
595
|
-
} else
|
|
596
|
-
|
|
609
|
+
} else {
|
|
610
|
+
// When chipFamily is not yet set (e.g., during GET_SECURITY_INFO in detectChip),
|
|
611
|
+
// assume modern chips use 4-byte status
|
|
612
|
+
if (opcode === ESP_GET_SECURITY_INFO) {
|
|
613
|
+
statusLen = 4;
|
|
614
|
+
} else if ([2, 4].includes(data.length)) {
|
|
615
|
+
statusLen = data.length;
|
|
616
|
+
}
|
|
597
617
|
}
|
|
598
|
-
}
|
|
599
618
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
619
|
+
if (data.length < statusLen) {
|
|
620
|
+
throw new Error("Didn't get enough status bytes");
|
|
621
|
+
}
|
|
622
|
+
const status = data.slice(-statusLen, data.length);
|
|
623
|
+
data = data.slice(0, -statusLen);
|
|
624
|
+
if (this.debug) {
|
|
625
|
+
this.logger.debug("status", status);
|
|
626
|
+
this.logger.debug("value", value);
|
|
627
|
+
this.logger.debug("data", data);
|
|
628
|
+
}
|
|
629
|
+
if (status[0] == 1) {
|
|
630
|
+
if (status[1] == ROM_INVALID_RECV_MSG) {
|
|
631
|
+
// Unsupported command can result in more than one error response
|
|
632
|
+
// Use drainInputBuffer for CP210x compatibility on Windows
|
|
633
|
+
await this.drainInputBuffer(200);
|
|
634
|
+
throw new Error("Invalid (unsupported) command " + toHex(opcode));
|
|
635
|
+
} else {
|
|
636
|
+
throw new Error("Command failure error code " + toHex(status[1]));
|
|
637
|
+
}
|
|
618
638
|
}
|
|
619
|
-
}
|
|
620
639
|
|
|
621
|
-
|
|
640
|
+
return [value, data];
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
// Chain command execution through the lock
|
|
644
|
+
// Use both .then() handlers to ensure lock continues even on error
|
|
645
|
+
this._commandLock = this._commandLock.then(executeCommand, executeCommand);
|
|
646
|
+
return this._commandLock;
|
|
622
647
|
}
|
|
623
648
|
|
|
624
649
|
/**
|
|
@@ -819,6 +844,25 @@ export class ESPLoader extends EventTarget {
|
|
|
819
844
|
|
|
820
845
|
async reconfigurePort(baud: number) {
|
|
821
846
|
try {
|
|
847
|
+
this._isReconfiguring = true;
|
|
848
|
+
|
|
849
|
+
// Wait for pending writes to complete
|
|
850
|
+
try {
|
|
851
|
+
await this._writeChain;
|
|
852
|
+
} catch (err) {
|
|
853
|
+
this.logger.debug(`Pending write error during reconfigure: ${err}`);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// Release persistent writer before closing
|
|
857
|
+
if (this._writer) {
|
|
858
|
+
try {
|
|
859
|
+
this._writer.releaseLock();
|
|
860
|
+
} catch (err) {
|
|
861
|
+
this.logger.debug(`Writer release error during reconfigure: ${err}`);
|
|
862
|
+
}
|
|
863
|
+
this._writer = undefined;
|
|
864
|
+
}
|
|
865
|
+
|
|
822
866
|
// SerialPort does not allow to be reconfigured while open so we close and re-open
|
|
823
867
|
// reader.cancel() causes the Promise returned by the read() operation running on
|
|
824
868
|
// the readLoop to return immediately with { value: undefined, done: true } and thus
|
|
@@ -837,6 +881,8 @@ export class ESPLoader extends EventTarget {
|
|
|
837
881
|
} catch (e) {
|
|
838
882
|
this.logger.error(`Reconfigure port error: ${e}`);
|
|
839
883
|
throw new Error(`Unable to change the baud rate to ${baud}: ${e}`);
|
|
884
|
+
} finally {
|
|
885
|
+
this._isReconfiguring = false;
|
|
840
886
|
}
|
|
841
887
|
}
|
|
842
888
|
|
|
@@ -1583,18 +1629,98 @@ export class ESPLoader extends EventTarget {
|
|
|
1583
1629
|
return espStubLoader;
|
|
1584
1630
|
}
|
|
1585
1631
|
|
|
1632
|
+
__writer?: WritableStreamDefaultWriter<Uint8Array>;
|
|
1633
|
+
__writeChain: Promise<void> = Promise.resolve();
|
|
1634
|
+
|
|
1635
|
+
private get _writer(): WritableStreamDefaultWriter<Uint8Array> | undefined {
|
|
1636
|
+
return this._parent ? this._parent._writer : this.__writer;
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
private set _writer(
|
|
1640
|
+
value: WritableStreamDefaultWriter<Uint8Array> | undefined,
|
|
1641
|
+
) {
|
|
1642
|
+
if (this._parent) {
|
|
1643
|
+
this._parent._writer = value;
|
|
1644
|
+
} else {
|
|
1645
|
+
this.__writer = value;
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
private get _writeChain(): Promise<void> {
|
|
1650
|
+
return this._parent ? this._parent._writeChain : this.__writeChain;
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
private set _writeChain(value: Promise<void>) {
|
|
1654
|
+
if (this._parent) {
|
|
1655
|
+
this._parent._writeChain = value;
|
|
1656
|
+
} else {
|
|
1657
|
+
this.__writeChain = value;
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1586
1661
|
async writeToStream(data: number[]) {
|
|
1587
1662
|
if (!this.port.writable) {
|
|
1588
1663
|
this.logger.debug("Port writable stream not available, skipping write");
|
|
1589
1664
|
return;
|
|
1590
1665
|
}
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
writer.releaseLock();
|
|
1595
|
-
} catch (err) {
|
|
1596
|
-
this.logger.error(`Ignoring release lock error: ${err}`);
|
|
1666
|
+
|
|
1667
|
+
if (this._isReconfiguring) {
|
|
1668
|
+
throw new Error("Cannot write during port reconfiguration");
|
|
1597
1669
|
}
|
|
1670
|
+
|
|
1671
|
+
// Queue writes to prevent lock contention (critical for CP2102 on Windows)
|
|
1672
|
+
this._writeChain = this._writeChain
|
|
1673
|
+
.then(
|
|
1674
|
+
async () => {
|
|
1675
|
+
// Check if port is still writable before attempting write
|
|
1676
|
+
if (!this.port.writable) {
|
|
1677
|
+
throw new Error("Port became unavailable during write");
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
// Get or create persistent writer
|
|
1681
|
+
if (!this._writer) {
|
|
1682
|
+
try {
|
|
1683
|
+
this._writer = this.port.writable.getWriter();
|
|
1684
|
+
} catch (err) {
|
|
1685
|
+
this.logger.error(`Failed to get writer: ${err}`);
|
|
1686
|
+
throw err;
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
// Perform the write
|
|
1691
|
+
await this._writer.write(new Uint8Array(data));
|
|
1692
|
+
},
|
|
1693
|
+
async () => {
|
|
1694
|
+
// Previous write failed, but still attempt this write
|
|
1695
|
+
if (!this.port.writable) {
|
|
1696
|
+
throw new Error("Port became unavailable during write");
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
// Writer was likely cleaned up by previous error, create new one
|
|
1700
|
+
if (!this._writer) {
|
|
1701
|
+
this._writer = this.port.writable.getWriter();
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
await this._writer.write(new Uint8Array(data));
|
|
1705
|
+
},
|
|
1706
|
+
)
|
|
1707
|
+
.catch((err) => {
|
|
1708
|
+
this.logger.error(`Write error: ${err}`);
|
|
1709
|
+
// Ensure writer is cleaned up on any error
|
|
1710
|
+
if (this._writer) {
|
|
1711
|
+
try {
|
|
1712
|
+
this._writer.releaseLock();
|
|
1713
|
+
} catch (e) {
|
|
1714
|
+
// Ignore release errors
|
|
1715
|
+
}
|
|
1716
|
+
this._writer = undefined;
|
|
1717
|
+
}
|
|
1718
|
+
// Re-throw to propagate error
|
|
1719
|
+
throw err;
|
|
1720
|
+
});
|
|
1721
|
+
|
|
1722
|
+
// Always await the write chain to ensure errors are caught
|
|
1723
|
+
await this._writeChain;
|
|
1598
1724
|
}
|
|
1599
1725
|
|
|
1600
1726
|
async disconnect() {
|
|
@@ -1606,15 +1732,49 @@ export class ESPLoader extends EventTarget {
|
|
|
1606
1732
|
this.logger.debug("Port already closed, skipping disconnect");
|
|
1607
1733
|
return;
|
|
1608
1734
|
}
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1735
|
+
|
|
1736
|
+
try {
|
|
1737
|
+
this._isReconfiguring = true;
|
|
1738
|
+
|
|
1739
|
+
// Wait for pending writes to complete
|
|
1740
|
+
try {
|
|
1741
|
+
await this._writeChain;
|
|
1742
|
+
} catch (err) {
|
|
1743
|
+
this.logger.debug(`Pending write error during disconnect: ${err}`);
|
|
1613
1744
|
}
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1745
|
+
|
|
1746
|
+
// Release persistent writer before closing
|
|
1747
|
+
if (this._writer) {
|
|
1748
|
+
try {
|
|
1749
|
+
await this._writer.close();
|
|
1750
|
+
this._writer.releaseLock();
|
|
1751
|
+
} catch (err) {
|
|
1752
|
+
this.logger.debug(`Writer close/release error: ${err}`);
|
|
1753
|
+
}
|
|
1754
|
+
this._writer = undefined;
|
|
1755
|
+
} else {
|
|
1756
|
+
// No persistent writer exists, close stream directly
|
|
1757
|
+
// This path is taken when no writes have been queued
|
|
1758
|
+
try {
|
|
1759
|
+
const writer = this.port.writable.getWriter();
|
|
1760
|
+
await writer.close();
|
|
1761
|
+
writer.releaseLock();
|
|
1762
|
+
} catch (err) {
|
|
1763
|
+
this.logger.debug(`Direct writer close error: ${err}`);
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
await new Promise((resolve) => {
|
|
1768
|
+
if (!this._reader) {
|
|
1769
|
+
resolve(undefined);
|
|
1770
|
+
}
|
|
1771
|
+
this.addEventListener("disconnect", resolve, { once: true });
|
|
1772
|
+
this._reader!.cancel();
|
|
1773
|
+
});
|
|
1774
|
+
this.connected = false;
|
|
1775
|
+
} finally {
|
|
1776
|
+
this._isReconfiguring = false;
|
|
1777
|
+
}
|
|
1618
1778
|
}
|
|
1619
1779
|
|
|
1620
1780
|
/**
|
|
@@ -1627,99 +1787,122 @@ export class ESPLoader extends EventTarget {
|
|
|
1627
1787
|
return;
|
|
1628
1788
|
}
|
|
1629
1789
|
|
|
1630
|
-
|
|
1790
|
+
try {
|
|
1791
|
+
this._isReconfiguring = true;
|
|
1631
1792
|
|
|
1632
|
-
|
|
1633
|
-
this.__inputBuffer = [];
|
|
1793
|
+
this.logger.log("Reconnecting serial port...");
|
|
1634
1794
|
|
|
1635
|
-
|
|
1636
|
-
|
|
1795
|
+
this.connected = false;
|
|
1796
|
+
this.__inputBuffer = [];
|
|
1797
|
+
|
|
1798
|
+
// Wait for pending writes to complete
|
|
1637
1799
|
try {
|
|
1638
|
-
await this.
|
|
1800
|
+
await this._writeChain;
|
|
1639
1801
|
} catch (err) {
|
|
1640
|
-
this.logger.debug(`
|
|
1802
|
+
this.logger.debug(`Pending write error during reconnect: ${err}`);
|
|
1641
1803
|
}
|
|
1642
|
-
this._reader = undefined;
|
|
1643
|
-
}
|
|
1644
1804
|
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
this.logger.debug("Opening port...");
|
|
1655
|
-
try {
|
|
1656
|
-
await this.port.open({ baudRate: ESP_ROM_BAUD });
|
|
1657
|
-
this.connected = true;
|
|
1658
|
-
} catch (err) {
|
|
1659
|
-
throw new Error(`Failed to open port: ${err}`);
|
|
1660
|
-
}
|
|
1805
|
+
// Release persistent writer
|
|
1806
|
+
if (this._writer) {
|
|
1807
|
+
try {
|
|
1808
|
+
this._writer.releaseLock();
|
|
1809
|
+
} catch (err) {
|
|
1810
|
+
this.logger.debug(`Writer release error during reconnect: ${err}`);
|
|
1811
|
+
}
|
|
1812
|
+
this._writer = undefined;
|
|
1813
|
+
}
|
|
1661
1814
|
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1815
|
+
// Cancel reader
|
|
1816
|
+
if (this._reader) {
|
|
1817
|
+
try {
|
|
1818
|
+
await this._reader.cancel();
|
|
1819
|
+
} catch (err) {
|
|
1820
|
+
this.logger.debug(`Reader cancel error: ${err}`);
|
|
1821
|
+
}
|
|
1822
|
+
this._reader = undefined;
|
|
1823
|
+
}
|
|
1668
1824
|
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1825
|
+
// Close port
|
|
1826
|
+
try {
|
|
1827
|
+
await this.port.close();
|
|
1828
|
+
this.logger.log("Port closed");
|
|
1829
|
+
} catch (err) {
|
|
1830
|
+
this.logger.debug(`Port close error: ${err}`);
|
|
1831
|
+
}
|
|
1675
1832
|
|
|
1676
|
-
|
|
1677
|
-
|
|
1833
|
+
// Open the port
|
|
1834
|
+
this.logger.debug("Opening port...");
|
|
1835
|
+
try {
|
|
1836
|
+
await this.port.open({ baudRate: ESP_ROM_BAUD });
|
|
1837
|
+
this.connected = true;
|
|
1838
|
+
} catch (err) {
|
|
1839
|
+
throw new Error(`Failed to open port: ${err}`);
|
|
1840
|
+
}
|
|
1678
1841
|
|
|
1679
|
-
|
|
1680
|
-
this.
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1842
|
+
// Verify port streams are available
|
|
1843
|
+
if (!this.port.readable || !this.port.writable) {
|
|
1844
|
+
throw new Error(
|
|
1845
|
+
`Port streams not available after open (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`,
|
|
1846
|
+
);
|
|
1847
|
+
}
|
|
1684
1848
|
|
|
1685
|
-
|
|
1686
|
-
|
|
1849
|
+
// Save chip info and flash size (no need to detect again)
|
|
1850
|
+
const savedChipFamily = this.chipFamily;
|
|
1851
|
+
const savedChipName = this.chipName;
|
|
1852
|
+
const savedChipRevision = this.chipRevision;
|
|
1853
|
+
const savedChipVariant = this.chipVariant;
|
|
1854
|
+
const savedFlashSize = this.flashSize;
|
|
1687
1855
|
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
this.chipName = savedChipName;
|
|
1691
|
-
this.chipRevision = savedChipRevision;
|
|
1692
|
-
this.chipVariant = savedChipVariant;
|
|
1693
|
-
this.flashSize = savedFlashSize;
|
|
1856
|
+
// Reinitialize
|
|
1857
|
+
await this.hardReset(true);
|
|
1694
1858
|
|
|
1695
|
-
|
|
1859
|
+
if (!this._parent) {
|
|
1860
|
+
this.__inputBuffer = [];
|
|
1861
|
+
this.__totalBytesRead = 0;
|
|
1862
|
+
this.readLoop();
|
|
1863
|
+
}
|
|
1696
1864
|
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
throw new Error("Port not ready after reconnect");
|
|
1700
|
-
}
|
|
1865
|
+
await this.flushSerialBuffers();
|
|
1866
|
+
await this.sync();
|
|
1701
1867
|
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1868
|
+
// Restore chip info
|
|
1869
|
+
this.chipFamily = savedChipFamily;
|
|
1870
|
+
this.chipName = savedChipName;
|
|
1871
|
+
this.chipRevision = savedChipRevision;
|
|
1872
|
+
this.chipVariant = savedChipVariant;
|
|
1873
|
+
this.flashSize = savedFlashSize;
|
|
1705
1874
|
|
|
1706
|
-
|
|
1707
|
-
if (this._currentBaudRate !== ESP_ROM_BAUD) {
|
|
1708
|
-
await stubLoader.setBaudrate(this._currentBaudRate);
|
|
1875
|
+
this.logger.debug(`Reconnect complete (chip: ${this.chipName})`);
|
|
1709
1876
|
|
|
1710
|
-
// Verify port is
|
|
1877
|
+
// Verify port is ready
|
|
1711
1878
|
if (!this.port.writable || !this.port.readable) {
|
|
1712
|
-
throw new Error(
|
|
1713
|
-
`Port not ready after baudrate change (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`,
|
|
1714
|
-
);
|
|
1879
|
+
throw new Error("Port not ready after reconnect");
|
|
1715
1880
|
}
|
|
1716
|
-
}
|
|
1717
1881
|
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1882
|
+
// Load stub
|
|
1883
|
+
const stubLoader = await this.runStub(true);
|
|
1884
|
+
this.logger.debug("Stub loaded");
|
|
1885
|
+
|
|
1886
|
+
// Restore baudrate if it was changed
|
|
1887
|
+
if (this._currentBaudRate !== ESP_ROM_BAUD) {
|
|
1888
|
+
await stubLoader.setBaudrate(this._currentBaudRate);
|
|
1889
|
+
|
|
1890
|
+
// Verify port is still ready after baudrate change
|
|
1891
|
+
if (!this.port.writable || !this.port.readable) {
|
|
1892
|
+
throw new Error(
|
|
1893
|
+
`Port not ready after baudrate change (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`,
|
|
1894
|
+
);
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
// Copy stub state to this instance if we're a stub loader
|
|
1899
|
+
if (this.IS_STUB) {
|
|
1900
|
+
Object.assign(this, stubLoader);
|
|
1901
|
+
}
|
|
1902
|
+
this.logger.debug("Reconnection successful");
|
|
1903
|
+
} finally {
|
|
1904
|
+
this._isReconfiguring = false;
|
|
1721
1905
|
}
|
|
1722
|
-
this.logger.debug("Reconnection successful");
|
|
1723
1906
|
}
|
|
1724
1907
|
|
|
1725
1908
|
/**
|
package/src/stubs/README.md
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
# Licensing
|
|
2
2
|
|
|
3
|
-
The binaries in JSON format distributed in this directory are released as Free Software under GNU General Public License Version 2 or later.
|
|
3
|
+
The binaries in JSON format distributed in this directory are released as Free Software under GNU General Public License Version 2 or later. The sources can be obtained from https://github.com/espressif/esptool-legacy-flasher-stub/
|
package/src/stubs/esp32c3.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"entry":
|
|
3
|
-
"text": "QRG3NwRgIsQmwkrAEUcGxrdEyD/Yyz6JM4TnAJOEBAAcQJGLmeeyQCJEkkQCSUEBgoADJQkAnEATdfUPgpfNtwERtwcAYE7Gg6mHAErIN0nIPybKUsQGziLMk4THAT6KEwkJAIBAE3T0PxnIAyUKAIMnCQB9FBN19Q+Cl2X43bfyQGJEtwcAYCOoNwHSREJJskkiSgVhgoCTBwAMkEEqh2MY9QCFRwXGI6AFAHlVgoCFRmMH1gAJRWMNpgB9VYKAQgWTB7ANQYVjE/cCiUecwfW3EwbADWMVxwCUwT6FgoCTB9AN4xz3/JTBEwWwDYKAt3XJP0ERk4XFugbGcT9jTQUEt3fJP5OHR7IDpwcIg9ZHCBOGFgAjkscINpcjAKcAA9dHCJFnk4cHBGMa9wI398g/EwdHsqFnupcDpgcItzbJP5OGRrZjH+YAI6bHCCOg1wgjkgcIIaD5V+MK9fyyQEEBgoAjptcII6DnCN23NycAYBMHRwUcQ52L9f83NwBgEwdHBRxDnYv1/4KAQREGxvk/NycAYLcGAAgjJgcCkwfHAhTDFEP9/ohDskATRfX/BYlBAYKAQREGxsk/fd23JwBgNwcAQJjDmEN9/7JAQQGCgEERJsK3xMg/k4REAUrAA6kEAQbGIsRjCQkERTcxxb1HAURj1icBgER9jBM0FABdP7U3mES3BwABPoaTFscAGcA3BoAA/Rf1j7cmAGDcwpDCnEL9/5MH9P/Fm8EHMwn5QD6XI6gkAZjEskAiRJJEAklBAYKAAREGzhU3NwXOP2wAURWXAMj/54CA8KqHBUWd57JHk/cHID7GsTe3JwBgmEe3BkAANwXOP1WPmMeyRVEVlwDI/+eA4O0zNaAA8kAFYYKAQRG3x8g/BsaTh0cBBUcjgOcAE9fFAJjHBWd9F8zDyMf5jTqVqpWxgQ1njMsjqgcAMzbAALqXI4bHsKU/GcETBVAMskBBAYKAeXEi1DfEyD8m0k7OLsYG1krQqokTBEQBlwDI/+eAQOKyRUREY/OVAK6EucgDKUQAJpkTWckAHEhjVfAAHERjX/kCvTV93UhAJobOhZcAyP/ngIDeAcWTB0AMXMhcQLJQAlmml1zAXETySYWPXMQiVJJURWEXA8j/ZwDD3K09Zb+yUCJUklQCWfJJRWGCgAERIsw3xMg/EwREAY1nopeDx8ewBs4mykrITsaBy2JE8kDSREJJskkFYaG3RERj85UAroSxwAMpRACqiSaZE1nJABxIY1XwABxEY175AtE7fd1IQCaGzoWXAMj/54Cg1hN19Q8BxZMHQAxcyFxAppdcwFxEhY9cxPJAYkTSREJJskkFYYKAzTNtv0ERBsaXAMj/54CAywNFhQGyQHUVEzUVAEEBgoBBEQbGxTcNzTdHyD8TBwcAXEOdxxBHDca3BgxgmEYNinGbUY+YxgVmNwcMYDRPEwYGwPGPfXYTBvY/8Y7VjzzPskBBAYKAQREmwgbGIsRKwKqEST8h4SJEskACSSaFkkRBARcDyP9nAGO/KUWXAMj/54BAvVkUgycJAIWDhYuR4230skAiRLc3BGCEwwJJkkRBAYKAYWQ3OQRgEwQEahEJ2b9BEQbGEwcADGMa5QATBbANUT8TBcANskBBAWm3EwewDeMb5f5BNxMF0A31t0ERIsQmwgbGKoSzBLUAYxeUALJAIkSSREEBgoADRQQABQRNP+23dXEixSbD0twGx0rBzt4TAQGAEwEBgKqEKAguhAVqlwDI/+eAIA8N5CgALAiXAMj/54DADigAwUVNNwFFhWIWkbpAKkSaRApJ9llmWklhgoAiiWNzigAFaUqGjBgmhZcAyP/ngOC8E3X1DwHtSoaMGCgIlwDI/+
|
|
2
|
+
"entry": 1077413654,
|
|
3
|
+
"text": "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",
|
|
4
4
|
"text_start": 1077411840,
|
|
5
|
-
"data": "
|
|
5
|
+
"data": "FEDIP9oKOEBECzhA1gs4QKoMOEASDThAwAw4QLQJOEBmDDhApgw4QPILOEBkCThAGgw4QGQJOEC4CjhAAgs4QEQLOEDWCzhAygo4QNwJOEAoCjhAxgo4QAwPOEBECzhAzg04QMgOOEAiCThA7g44QCIJOEAiCThAIgk4QCIJOEAiCThAIgk4QCIJOEAiCThAdA04QCIJOEDmDThAyA44QA==",
|
|
6
6
|
"data_start": 1070164916,
|
|
7
7
|
"bss_start": 1070088192
|
|
8
8
|
}
|
package/src/stubs/esp32c5.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"entry":
|
|
3
|
-
"text": "QRG39wBgIsQmwkrAEUcGxrcEhEDYyz6JM4TnAJOEBAAcQJGLmeeyQCJEkkQCSUEBgoADJQkAnEATdfUPgpfNtwERtwcAYE7Gg6mHAErINwmEQCbKUsQGziLMk4THAT6KEwkJAIBAE3T0PxnIAyUKAIMnCQB9FBN19Q+Cl2X43bfyQGJEtwcAYCOoNwHSREJJskkiSgVhgoCTBwAMkEEqh2MY9QCFRwXGI6AFAHlVgoCFRmMH1gAJRWMNpgB9VYKAQgWTB7ANQYVjE/cCiUecwfW3EwbADWMVxwCUwT6FgoCTB9AN4xz3/JTBEwWwDYKAtzWFQEERk4XFugbGcT9jTQUEtzeFQJOHR7IDpwcIg9ZHCBOGFgAjkscINpcjAKcAA9dHCJFnk4cHBGMa9wI3t4RAEwdHsqFnupcDpgcIt/aEQJOGRrZjH+YAI6bHCCOg1wgjkgcIIaD5V+MK9fyyQEEBgoAjptcII6DnCN23NzcAYBMHRwUcQ52L9f83JwBgEwdHBRxDnYv1/4KAQREGxvk/NzcAYLcGAAgjJgcCkwfHAhTDFEP9/ohDskATRfX/BYlBAYKAQREGxsk/fd23NwBgNwcAQJjDmEN9/
|
|
2
|
+
"entry": 1082133196,
|
|
3
|
+
"text": "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",
|
|
4
4
|
"text_start": 1082130432,
|
|
5
|
-
"data": "
|
|
5
|
+
"data": "FACEQDAPgECaD4BALhCAQAIRgEBqEYBAGBGAQIoNgEC+EIBA/hCAQEoQgEA6DYBAchCAQDoNgEAMD4BAWA+AQJoPgEAuEIBAHg+AQLINgEDgDYBAGg+AQGQTgECaD4BAJhKAQCATgED0DIBARhOAQPQMgED0DIBA9AyAQPQMgED0DIBA9AyAQPQMgED0DIBAzBGAQPQMgEA+EoBAIBOAQA==",
|
|
6
6
|
"data_start": 1082469300,
|
|
7
7
|
"bss_start": 1082392576
|
|
8
8
|
}
|