tasmota-webserial-esptool 9.2.20 → 9.2.21

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/src/esp_loader.ts CHANGED
@@ -84,14 +84,6 @@ import {
84
84
  ESP32S3_RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK,
85
85
  ESP32C3_EFUSE_RD_MAC_SPI_SYS_3_REG,
86
86
  ESP32C3_EFUSE_RD_MAC_SPI_SYS_5_REG,
87
- ESP32C3_RTC_CNTL_WDTWPROTECT_REG,
88
- ESP32C3_RTC_CNTL_WDTCONFIG0_REG,
89
- ESP32C3_RTC_CNTL_WDTCONFIG1_REG,
90
- ESP32C3_RTC_CNTL_WDT_WKEY,
91
- ESP32C5_C6_RTC_CNTL_WDTWPROTECT_REG,
92
- ESP32C5_C6_RTC_CNTL_WDTCONFIG0_REG,
93
- ESP32C5_C6_RTC_CNTL_WDTCONFIG1_REG,
94
- ESP32C5_C6_RTC_CNTL_WDT_WKEY,
95
87
  ESP32C5_UART_CLKDIV_REG,
96
88
  ESP32C5_PCR_SYSCLK_CONF_REG,
97
89
  ESP32C5_PCR_SYSCLK_XTAL_FREQ_V,
@@ -1015,7 +1007,8 @@ export class ESPLoader extends EventTarget {
1015
1007
  private async runSignalSequence(
1016
1008
  steps: Array<{ dtr?: boolean; rts?: boolean; delayMs?: number }>,
1017
1009
  ): Promise<void> {
1018
- const webusb = (this.port as any).isWebUSB === true;
1010
+ const webusb =
1011
+ (this.port as unknown as { isWebUSB?: boolean }).isWebUSB === true;
1019
1012
  for (const step of steps) {
1020
1013
  if (step.dtr !== undefined && step.rts !== undefined) {
1021
1014
  if (webusb) {
@@ -1549,7 +1542,7 @@ export class ESPLoader extends EventTarget {
1549
1542
  `Connected CDC/JTAG successfully with ${strategy.name} reset.`,
1550
1543
  );
1551
1544
  return;
1552
- } catch (_error) {
1545
+ } catch {
1553
1546
  throw new Error("Sync timeout or abandoned");
1554
1547
  }
1555
1548
  }
@@ -1588,18 +1581,20 @@ export class ESPLoader extends EventTarget {
1588
1581
 
1589
1582
  /**
1590
1583
  * @name watchdogReset
1591
- * Watchdog reset for ESP32-S2/S3/C3 with USB-OTG or USB-JTAG/Serial
1584
+ * Watchdog reset for ESP32-S2/S3/P4 with USB-OTG or USB-JTAG/Serial
1592
1585
  * Uses RTC watchdog timer to reset the chip - works when DTR/RTS signals are not available
1593
1586
  * This is an alias for rtcWdtResetChipSpecific() for backwards compatibility
1587
+ * Note: ESP32-C3, ESP32-C5, ESP32-C6 do NOT boot correctly after WDT reset
1594
1588
  */
1595
1589
  async watchdogReset() {
1596
1590
  await this.rtcWdtResetChipSpecific();
1597
1591
  }
1598
1592
 
1599
1593
  /**
1600
- * RTC watchdog timer reset for ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C5, ESP32-C6, and ESP32-P4
1594
+ * RTC watchdog timer reset for ESP32-S2, ESP32-S3, and ESP32-P4
1601
1595
  * Uses specific registers for each chip family
1602
- * Note: ESP32-H2 does NOT support WDT reset
1596
+ * Note: ESP32-C3 does NOT boot correctly after WDT reset
1597
+ * Note: ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2 do NOT support WDT reset (no usable RTC WDT path)
1603
1598
  */
1604
1599
  public async rtcWdtResetChipSpecific(): Promise<void> {
1605
1600
  this.logger.debug("Hard resetting with watchdog timer...");
@@ -1619,20 +1614,6 @@ export class ESPLoader extends EventTarget {
1619
1614
  WDTCONFIG0_REG = ESP32S3_RTC_CNTL_WDTCONFIG0_REG;
1620
1615
  WDTCONFIG1_REG = ESP32S3_RTC_CNTL_WDTCONFIG1_REG;
1621
1616
  WDT_WKEY = ESP32S3_RTC_CNTL_WDT_WKEY;
1622
- } else if (this.chipFamily === CHIP_FAMILY_ESP32C3) {
1623
- WDTWPROTECT_REG = ESP32C3_RTC_CNTL_WDTWPROTECT_REG;
1624
- WDTCONFIG0_REG = ESP32C3_RTC_CNTL_WDTCONFIG0_REG;
1625
- WDTCONFIG1_REG = ESP32C3_RTC_CNTL_WDTCONFIG1_REG;
1626
- WDT_WKEY = ESP32C3_RTC_CNTL_WDT_WKEY;
1627
- } else if (
1628
- this.chipFamily === CHIP_FAMILY_ESP32C5 ||
1629
- this.chipFamily === CHIP_FAMILY_ESP32C6
1630
- ) {
1631
- // C5 and C6 use LP_WDT (Low Power Watchdog Timer)
1632
- WDTWPROTECT_REG = ESP32C5_C6_RTC_CNTL_WDTWPROTECT_REG;
1633
- WDTCONFIG0_REG = ESP32C5_C6_RTC_CNTL_WDTCONFIG0_REG;
1634
- WDTCONFIG1_REG = ESP32C5_C6_RTC_CNTL_WDTCONFIG1_REG;
1635
- WDT_WKEY = ESP32C5_C6_RTC_CNTL_WDT_WKEY;
1636
1617
  } else if (this.chipFamily === CHIP_FAMILY_ESP32P4) {
1637
1618
  // P4 uses LP_WDT (Low Power Watchdog Timer)
1638
1619
  WDTWPROTECT_REG = ESP32P4_RTC_CNTL_WDTWPROTECT_REG;
@@ -1697,7 +1678,6 @@ export class ESPLoader extends EventTarget {
1697
1678
  usbMode = { mode: "usb-jtag-serial", uartNo: 0 };
1698
1679
  }
1699
1680
 
1700
- // Check if chip supports WDT reset
1701
1681
  // WDT reset is not needed for ESP32-C3
1702
1682
  // WDT reset is supported by: ESP32-S2, ESP32-S3, ESP32-P4
1703
1683
  // WDT reset is NOT supported by: ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2
@@ -1841,60 +1821,75 @@ export class ESPLoader extends EventTarget {
1841
1821
  const isUsbJtagOrOtg = await this.detectUsbConnectionType();
1842
1822
 
1843
1823
  if (isUsbJtagOrOtg) {
1844
- // USB-JTAG/OTG devices: Use WDT reset
1845
- this.logger.debug("USB-JTAG/OTG detected - using WDT reset");
1824
+ // USB-JTAG/OTG devices: Check if chip supports WDT reset
1825
+ // Only S2, S3, P4 support WDT reset correctly
1826
+ // C3, C5, C6, C61, H2 do NOT boot correctly after WDT reset
1827
+ const supportsWdtReset =
1828
+ this.chipFamily === CHIP_FAMILY_ESP32S2 ||
1829
+ this.chipFamily === CHIP_FAMILY_ESP32S3 ||
1830
+ this.chipFamily === CHIP_FAMILY_ESP32P4;
1846
1831
 
1847
- // Get USB mode details
1848
- let usbMode: {
1849
- mode: "uart" | "usb-jtag-serial" | "usb-otg";
1850
- uartNo: number;
1851
- };
1852
- try {
1853
- usbMode = await this.getUsbMode();
1854
- this.logger.debug(
1855
- `USB mode: ${usbMode.mode} (uartNo=${usbMode.uartNo})`,
1856
- );
1857
- } catch (err) {
1858
- this.logger.debug(`Could not get USB mode: ${err}`);
1859
- usbMode = { mode: "usb-jtag-serial", uartNo: 0 };
1860
- }
1832
+ if (supportsWdtReset) {
1833
+ this.logger.debug("USB-JTAG/OTG detected - using WDT reset");
1861
1834
 
1862
- // Clear force download flag for USB-OTG devices
1863
- if (usbMode.mode === "usb-otg") {
1835
+ // Get USB mode details
1836
+ let usbMode: {
1837
+ mode: "uart" | "usb-jtag-serial" | "usb-otg";
1838
+ uartNo: number;
1839
+ };
1864
1840
  try {
1865
- const flagCleared = await this._clearForceDownloadBootIfNeeded();
1866
- if (flagCleared) {
1867
- this.logger.debug("Force download boot flag cleared");
1868
- }
1841
+ usbMode = await this.getUsbMode();
1842
+ this.logger.debug(
1843
+ `USB mode: ${usbMode.mode} (uartNo=${usbMode.uartNo})`,
1844
+ );
1869
1845
  } catch (err) {
1870
- this.logger.debug(`Could not clear force download flag: ${err}`);
1846
+ this.logger.debug(`Could not get USB mode: ${err}`);
1847
+ usbMode = { mode: "usb-jtag-serial", uartNo: 0 };
1871
1848
  }
1872
- }
1873
1849
 
1874
- // Perform WDT reset
1875
- await this.rtcWdtResetChipSpecific();
1876
- this.logger.debug(`${this.chipName}: WDT reset to firmware complete`);
1877
- return;
1850
+ // Clear force download flag for USB-OTG devices
1851
+ if (usbMode.mode === "usb-otg") {
1852
+ try {
1853
+ const flagCleared = await this._clearForceDownloadBootIfNeeded();
1854
+ if (flagCleared) {
1855
+ this.logger.debug("Force download boot flag cleared");
1856
+ }
1857
+ } catch (err) {
1858
+ this.logger.debug(`Could not clear force download flag: ${err}`);
1859
+ }
1860
+ }
1861
+
1862
+ // Perform WDT reset
1863
+ await this.rtcWdtResetChipSpecific();
1864
+ this.logger.debug(`${this.chipName}: WDT reset to firmware complete`);
1865
+ return;
1866
+ } else {
1867
+ // C3, C5, C6, etc. - use classic reset (like external serial chips)
1868
+ this.logger.debug(
1869
+ `${this.chipName} does not support WDT reset - using classic reset instead`,
1870
+ );
1871
+ }
1878
1872
  } else {
1879
1873
  // External serial chip: Use classic reset
1880
1874
  this.logger.debug(
1881
1875
  "External serial chip detected - using classic reset",
1882
1876
  );
1877
+ }
1883
1878
 
1884
- if (this.isWebUSB()) {
1885
- // WebUSB: Use longer delays for better compatibility
1886
- await this.setRTSWebUSB(true); // EN->LOW
1887
- await sleep(200);
1888
- await this.setRTSWebUSB(false);
1889
- await sleep(200);
1890
- this.logger.debug("Hard reset to firmware (WebUSB).");
1891
- } else {
1892
- // Web Serial: Standard reset
1893
- await this.setRTS(true); // EN->LOW
1894
- await sleep(100);
1895
- await this.setRTS(false);
1896
- this.logger.debug("Hard reset to firmware.");
1897
- }
1879
+ // Classic reset: used for external serial chips and USB-JTAG chips that do not support WDT reset
1880
+ if (this.isWebUSB()) {
1881
+ // WebUSB: Use longer delays for better compatibility
1882
+ await this.setRTSWebUSB(true); // EN->LOW
1883
+ await sleep(200);
1884
+ await this.setRTSWebUSB(false);
1885
+ await sleep(200);
1886
+ this.logger.debug("Hard reset to firmware (WebUSB).");
1887
+ } else {
1888
+ // Web Serial: Standard reset
1889
+ await this.setRTS(true); // EN->LOW
1890
+ await sleep(100);
1891
+ await this.setRTS(false);
1892
+ this.logger.debug("Hard reset to firmware.");
1898
1893
  }
1899
1894
  }
1900
1895
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -2483,9 +2478,9 @@ export class ESPLoader extends EventTarget {
2483
2478
 
2484
2479
  // Restart Readloop
2485
2480
  this.readLoop();
2486
- } catch (_e) {
2487
- // this.logger.error(`Reconfigure port error: ${e}`);
2488
- // throw new Error(`Unable to change the baud rate to ${baud}: ${e}`);
2481
+ } catch {
2482
+ // this.logger.error(`Reconfigure port error`);
2483
+ // throw new Error(`Unable to change the baud rate to ${baud}`);
2489
2484
  } finally {
2490
2485
  // Always reset flag, even on error or early return
2491
2486
  this._isReconfiguring = false;
@@ -3276,8 +3271,8 @@ export class ESPLoader extends EventTarget {
3276
3271
  // Wait for pending writes to complete
3277
3272
  try {
3278
3273
  await this._writeChain;
3279
- } catch (_err) {
3280
- // this.logger.debug(`Pending write error during disconnect: ${err}`);
3274
+ } catch {
3275
+ // this.logger.debug("Pending write error during disconnect");
3281
3276
  }
3282
3277
 
3283
3278
  // Release persistent writer before closing
@@ -3285,8 +3280,8 @@ export class ESPLoader extends EventTarget {
3285
3280
  try {
3286
3281
  await this._writer.close();
3287
3282
  this._writer.releaseLock();
3288
- } catch (_err) {
3289
- // this.logger.debug(`Writer close/release error: ${err}`);
3283
+ } catch {
3284
+ // this.logger.debug("Writer close/release error");
3290
3285
  }
3291
3286
  this._writer = undefined;
3292
3287
  } else {
@@ -3296,8 +3291,8 @@ export class ESPLoader extends EventTarget {
3296
3291
  const writer = this.port.writable.getWriter();
3297
3292
  await writer.close();
3298
3293
  writer.releaseLock();
3299
- } catch (_err) {
3300
- // this.logger.debug(`Direct writer close error: ${err}`);
3294
+ } catch {
3295
+ // this.logger.debug("Direct writer close error");
3301
3296
  }
3302
3297
  }
3303
3298
 
@@ -3325,7 +3320,7 @@ export class ESPLoader extends EventTarget {
3325
3320
  // Only cancel if reader is still active
3326
3321
  try {
3327
3322
  this._reader.cancel();
3328
- } catch (_err) {
3323
+ } catch {
3329
3324
  // Reader already released, resolve immediately
3330
3325
  clearTimeout(timeout);
3331
3326
  resolve(undefined);
@@ -3356,8 +3351,8 @@ export class ESPLoader extends EventTarget {
3356
3351
  // Wait for pending writes to complete
3357
3352
  try {
3358
3353
  await this._writeChain;
3359
- } catch (_err) {
3360
- // this.logger.debug(`Pending write error during release: ${err}`);
3354
+ } catch {
3355
+ // this.logger.debug("Pending write error during release");
3361
3356
  }
3362
3357
 
3363
3358
  // Release writer
@@ -3556,7 +3551,9 @@ export class ESPLoader extends EventTarget {
3556
3551
  private async _ensureStreamsReady(): Promise<void> {
3557
3552
  if (this.isWebUSB()) {
3558
3553
  try {
3559
- await (this.port as any).recreateStreams();
3554
+ await (
3555
+ this.port as unknown as { recreateStreams(): Promise<void> }
3556
+ ).recreateStreams();
3560
3557
  this.logger.debug("WebUSB streams recreated");
3561
3558
 
3562
3559
  let retries = 30;