Main entry point for the ESP32 monitor application. Sets up argument parsing, initializes serial communication, starts background threads for serial monitoring and command input, and launches the memory usage graph. Implements graceful shutdown handling with signal processing for c
()
| 424 | |
| 425 | |
| 426 | def main() -> None: |
| 427 | """ |
| 428 | Main entry point for the ESP32 monitor application. |
| 429 | |
| 430 | Sets up argument parsing, initializes serial communication, starts background threads |
| 431 | for serial monitoring and command input, and launches the memory usage graph. |
| 432 | Implements graceful shutdown handling with signal processing for clean termination. |
| 433 | |
| 434 | Features: |
| 435 | - Serial port monitoring with color-coded output |
| 436 | - Real-time memory usage graphing |
| 437 | - Interactive command interface |
| 438 | - Screenshot capture capability |
| 439 | - Graceful shutdown on Ctrl-C or window close |
| 440 | """ |
| 441 | parser = build_arg_parser() |
| 442 | args = parser.parse_args() |
| 443 | port = args.port |
| 444 | if port is None: |
| 445 | port_list = get_auto_detected_port() |
| 446 | if len(port_list) == 1: |
| 447 | port = port_list[0] |
| 448 | print(f"{Fore.CYAN}Auto-detected serial port: {port}{Style.RESET_ALL}") |
| 449 | elif len(port_list) > 1: |
| 450 | print(f"{Fore.YELLOW}Multiple serial ports found:{Style.RESET_ALL}") |
| 451 | for p in port_list: |
| 452 | print(f" - {p}") |
| 453 | print( |
| 454 | f"{Fore.YELLOW}Please specify the desired port as a command-line argument.{Style.RESET_ALL}" |
| 455 | ) |
| 456 | if port is None: |
| 457 | print(f"{Fore.RED}Error: No suitable serial port found.{Style.RESET_ALL}") |
| 458 | sys.exit(1) |
| 459 | |
| 460 | try: |
| 461 | ser = serial.Serial(port, args.baud, timeout=0.1) |
| 462 | ser.dtr = False |
| 463 | ser.rts = False |
| 464 | except serial.SerialException as e: |
| 465 | print(f"{Fore.RED}Error opening port: {e}{Style.RESET_ALL}") |
| 466 | return |
| 467 | |
| 468 | # Set up signal handler for graceful shutdown |
| 469 | signal.signal(signal.SIGINT, signal_handler) |
| 470 | |
| 471 | # 1. Start the Serial Reader in a separate thread |
| 472 | # Daemon=True means this thread dies when the main program closes |
| 473 | myargs = vars(args) # Convert Namespace to dict for easier passing |
| 474 | t = threading.Thread(target=serial_worker, args=(ser, myargs), daemon=True) |
| 475 | t.start() |
| 476 | |
| 477 | # Start input thread |
| 478 | input_thread = threading.Thread(target=input_worker, args=(ser,), daemon=True) |
| 479 | input_thread.start() |
| 480 | |
| 481 | # 2. Set up the Graph (Main Thread) |
| 482 | try: |
| 483 | import matplotlib.style as mplstyle # pylint: disable=import-outside-toplevel |
no test coverage detected