diff --git a/core/archipelago/src/mesh/meshtastic.rs b/core/archipelago/src/mesh/meshtastic.rs index 2692e483..1245e5fe 100644 --- a/core/archipelago/src/mesh/meshtastic.rs +++ b/core/archipelago/src/mesh/meshtastic.rs @@ -180,6 +180,12 @@ impl MeshtasticDevice { "Failed to open serial port {} (permission denied? device busy?)", path ))?; + // See probe_rnode() in reticulum.rs for why: ESP32-S3 native-USB + // boards reset on a DTR/RTS transition, so deassert both and settle + // before the handshake below. + let _ = port.set_dtr(false); + let _ = port.set_rts(false); + tokio::time::sleep(Duration::from_millis(300)).await; info!(path = %path, baud = BAUD_RATE, "Opened Meshtastic serial port"); Ok(Self { diff --git a/core/archipelago/src/mesh/reticulum.rs b/core/archipelago/src/mesh/reticulum.rs index adf02218..d2b89085 100644 --- a/core/archipelago/src/mesh/reticulum.rs +++ b/core/archipelago/src/mesh/reticulum.rs @@ -1005,6 +1005,14 @@ fn parse_hash16(hex_str: &str) -> Result<[u8; 16]> { async fn probe_rnode(path: &str) -> Result<()> { let port = serial2_tokio::SerialPort::open(path, PROBE_BAUD) .with_context(|| format!("Failed to open {} for Reticulum probe", path))?; + // ESP32-S3 native-USB boards (Heltec V3/V4 etc. — no separate USB-UART + // bridge chip) treat a DTR/RTS transition on open as a reset signal, the + // same mechanism esptool uses to force bootloader entry. Deassert both + // and let the board settle before writing the probe, or the reboot eats + // the DETECT_RESP window below. + let _ = port.set_dtr(false); + let _ = port.set_rts(false); + tokio::time::sleep(Duration::from_millis(300)).await; let probe: [u8; 13] = [ KISS_FEND, KISS_CMD_DETECT, diff --git a/core/archipelago/src/mesh/serial.rs b/core/archipelago/src/mesh/serial.rs index 5eaac130..5358ff0f 100644 --- a/core/archipelago/src/mesh/serial.rs +++ b/core/archipelago/src/mesh/serial.rs @@ -57,6 +57,12 @@ impl MeshcoreDevice { "Failed to open serial port {} (permission denied? device busy?)", path ))?; + // See probe_rnode() in reticulum.rs for why: ESP32-S3 native-USB + // boards reset on a DTR/RTS transition, so deassert both and settle + // before the handshake below. + let _ = port.set_dtr(false); + let _ = port.set_rts(false); + tokio::time::sleep(Duration::from_millis(300)).await; info!(path = %path, baud = BAUD_RATE, "Opened serial port");