From bc1664dadefb689d011ecef0407d1fdbdcefc026 Mon Sep 17 00:00:00 2001 From: Dale Whinham Date: Thu, 20 Mar 2025 13:14:58 +0000 Subject: [PATCH] Work around RTS/DTR serial reset issues on Windows Some devices (e.g. Heltec V3.1) are reset when the RTS or DTR pins are messed with, which means that without workarounds, Meshtastic CLI will cause a reset with any operation that opens the serial port. This behavior is documented in this PySerial issue: https://github.com/pyserial/pyserial/issues/124 On Linux, we already handle this by disabling the HUPCL termios flag, which has the effect of preventing the offending lines being toggled. On Windows, setting the initial state of RTS and DTR before opening the port has a similar effect. Implement this workaround so that Meshtastic CLI can be used on Windows with these devices. --- meshtastic/serial_interface.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/meshtastic/serial_interface.py b/meshtastic/serial_interface.py index 39f2648..7133b39 100644 --- a/meshtastic/serial_interface.py +++ b/meshtastic/serial_interface.py @@ -46,7 +46,12 @@ class SerialInterface(StreamInterface): logging.debug(f"Connecting to {self.devPath}") - # first we need to set the HUPCL so the device will not reboot based on RTS and/or DTR + # set port to None to prevent automatically opening + self.stream = serial.Serial( + port=None, baudrate=115200, exclusive=True, timeout=0.5, write_timeout=0 + ) + + # first we need to clear HUPCL (UNIX) or clear RTS/DTR (Windows) so the device will not reboot based on RTS and/or DTR # see https://github.com/pyserial/pyserial/issues/124 if platform.system() != "Windows": with open(self.devPath, encoding="utf8") as f: @@ -55,10 +60,14 @@ class SerialInterface(StreamInterface): termios.tcsetattr(f, termios.TCSAFLUSH, attrs) f.close() time.sleep(0.1) + else: + self.stream.rts = 0 + self.stream.dtr = 0 + + # set proper port and open now that we've worked-around RTS/DTR issues + self.stream.port = self.devPath + self.stream.open() - self.stream = serial.Serial( - self.devPath, 115200, exclusive=True, timeout=0.5, write_timeout=0 - ) self.stream.flush() # type: ignore[attr-defined] time.sleep(0.1)