Skip to content

Commit

Permalink
Add --retry-open flag
Browse files Browse the repository at this point in the history
esp-idf-monitor frequently fails when trying to open the serial port of a device
which deep-sleeps often.

e.g.:

```
--- esp-idf-monitor 1.4.0 on /dev/cu.usbmodem6101 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
[Errno 2] could not open port /dev/cu.usbmodem6101: [Errno 2] No such file or directory: '/dev/cu.usbmodem6101'
Connection to /dev/cu.usbmodem6101 failed. Available ports:
/dev/cu.usbmodemF554393F21402
/dev/cu.AspergitosII
/dev/cu.Bluetooth-Incoming-Port
```

esp-idf-monitor currently already waits for the serial port _if_ it was
opened successfully. This, however, doesn't help when opening the device for the first time.

This PR adds a new flag `--retry-open` which retries opening the port indefinitely until the
device shows up:

```
--- esp-idf-monitor 1.4.0 on /dev/cu.usbmodem6101 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
[Errno 2] could not open port /dev/cu.usbmodem6101: [Errno 2] No such file or directory: '/dev/cu.usbmodem6101'
Retrying to open port ......
ESP-ROM:esp32s3-20210327

```
  • Loading branch information
2opremio committed Jul 16, 2024
1 parent 21732a7 commit cf54b56
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 13 deletions.
6 changes: 6 additions & 0 deletions esp_idf_monitor/base/argument_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,10 @@ def get_parser(): # type: () -> argparse.ArgumentParser
default=False,
action='store_true')

parser.add_argument(
'--retry-open',
help='Retry opening the port device for the first time if it does not exist',
default=False,
action='store_true')

return parser
43 changes: 31 additions & 12 deletions esp_idf_monitor/base/serial_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ class SerialReader(Reader):
event queue, until stopped.
"""

def __init__(self, serial_instance, event_queue, reset, target):
# type: (serial.Serial, queue.Queue, bool, str) -> None
def __init__(self, serial_instance, event_queue, reset, retry_open, target):
# type: (serial.Serial, queue.Queue, bool, bool, str) -> None
super(SerialReader, self).__init__()
self.baud = serial_instance.baudrate
self.serial = serial_instance
self.event_queue = event_queue
self.retry_open = retry_open
self.gdb_exit = False
self.reset = reset
self.reset_strategy = Reset(serial_instance, target)
Expand All @@ -43,16 +44,34 @@ def run(self):
# type: () -> None
if not self.serial.is_open:
self.serial.baudrate = self.baud
try:
# We can come to this thread at startup or from external application line GDB.
# If we come from GDB we would like to continue to run without reset.
self.open_serial(reset=not self.gdb_exit and self.reset)
except serial.SerialException as e:
print(e)
# if connection to port fails suggest other available ports
port_list = '\n'.join([p.device for p in list_ports.comports()])
yellow_print(f'Connection to {self.serial.portstr} failed. Available ports:\n{port_list}')
return
printed_failure = False
retry_attempts = 0
while True:
try:
# We can come to this thread at startup or from external application line GDB.
# If we come from GDB we would like to continue to run without reset.
self.open_serial(reset=not self.gdb_exit and self.reset)
if retry_attempts > 0:
# break the retrying line
print("")
break
except serial.SerialException as e:
if retry_attempts == 0:
print(e)
if self.retry_open:
# only print this once
yellow_print("Retrying to open port ", newline='')
if self.retry_open:
if retry_attempts % 9 == 0:
# print a dot every second
yellow_print(".", newline='')
time.sleep(0.1)
retry_attempts += 1
continue
# if connection to port fails suggest other available ports
port_list = '\n'.join([p.device for p in list_ports.comports()])
yellow_print(f'Connection to {self.serial.portstr} failed. Available ports:\n{port_list}')
return
self.gdb_exit = False
try:
while self.alive:
Expand Down
4 changes: 3 additions & 1 deletion esp_idf_monitor/idf_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def __init__(
make='make', # type: str
encrypted=False, # type: bool
reset=DEFAULT_TARGET_RESET, # type: bool
retry_open=False, # type: bool
toolchain_prefix=DEFAULT_TOOLCHAIN_PREFIX, # type: str
eol='CRLF', # type: str
decode_coredumps=COREDUMP_DECODE_INFO, # type: str
Expand Down Expand Up @@ -128,7 +129,7 @@ def __init__(
# testing hook: when running tests, input from console is ignored
socket_test_mode = os.environ.get('ESP_IDF_MONITOR_TEST') == '1'
self.serial = serial_instance
self.serial_reader = SerialReader(self.serial, self.event_queue, reset, target) # type: Reader
self.serial_reader = SerialReader(self.serial, self.event_queue, reset, retry_open, target) # type: Reader

self.gdb_helper = GDBHelper(toolchain_prefix, websocket_client, self.elf_file, self.serial.port,
self.serial.baudrate) if self.elf_exists else None
Expand Down Expand Up @@ -408,6 +409,7 @@ def main() -> None:
args.make,
args.encrypted,
not args.no_reset,
args.retry_open,
args.toolchain_prefix,
args.eol,
args.decode_coredumps,
Expand Down

0 comments on commit cf54b56

Please sign in to comment.