diff --git a/README.md b/README.md index 7fa6119..5549b8f 100644 --- a/README.md +++ b/README.md @@ -2496,6 +2496,12 @@ The checksum is the sum of the first four bytes modulo 256. Firmware and Python ### Finding your USB↔UART adapter “description” (port filtering) If you have multiple serial/COM devices, you can filter which ports the bridge will consider using the port **description** (or vendor/product text) shown by the OS. +Run `uv run controller-uart-bridge --list-ports` to print port names, +descriptions, and manufacturers, then exit without opening any ports or starting +controller discovery. This uses the same USB-only default and port filters as +the bridge; add `--all-ports` to include non-USB serial devices, or +`--include-port-desc CP210` to preview a description filter. + - **macOS/Linux (terminal)**: - Quick list with descriptions: `python -m serial.tools.list_ports -v` - Then run the bridge with a filter, for example: `controller-uart-bridge --interactive --include-port-desc CP210` @@ -2653,6 +2659,7 @@ Options: - `--map index:PORT` (repeatable) to pin controller index to serial (e.g., `--map 0:/dev/cu.usbserial-0001` or `--map 0:COM5`). - `--ports PORTS...` or `--interactive` for auto/interactive pairing. - `--all-ports` to include non-USB serial devices in discovery. +- `--list-ports` to print serial port names, descriptions, and manufacturers, then exit (respects port filters and `--all-ports`). - `--ignore-port-desc SUBSTR` / `--include-port-desc SUBSTR` to filter serial ports by description (repeatable). - `--include-controller-name SUBSTR` to only open controllers whose name matches (repeatable). - `--list-controllers` to print detected controllers and their GUIDs, then exit (useful for GUID-based options). diff --git a/src/switch_pico_bridge/controller_uart_bridge.py b/src/switch_pico_bridge/controller_uart_bridge.py index 907385c..8a29484 100644 --- a/src/switch_pico_bridge/controller_uart_bridge.py +++ b/src/switch_pico_bridge/controller_uart_bridge.py @@ -32,6 +32,7 @@ import sdl3 from rich.console import Console from rich.prompt import Prompt from rich.table import Table +from rich.text import Text from .switch_pico_uart import ( UART_BAUD, @@ -641,6 +642,11 @@ def build_arg_parser() -> argparse.ArgumentParser: action="store_true", help="Include non-USB serial ports when listing devices.", ) + parser.add_argument( + "--list-ports", + action="store_true", + help="List serial ports, descriptions, and manufacturers, then exit. Uses port filters and --all-ports.", + ) parser.add_argument( "--frequency", type=float, @@ -1002,6 +1008,32 @@ def list_controllers_with_guids( console.print(table) +def list_serial_ports(console: Console, args: argparse.Namespace) -> None: + """Show available UART ports without opening them or initializing SDL.""" + ports = discover_serial_ports( + include_non_usb=args.all_ports, + ignore_descriptions=args.ignore_port_desc, + include_descriptions=args.include_port_desc, + include_manufacturers=args.include_port_manufacturer, + ) + if not ports: + console.print("No matching serial ports found.") + if not args.all_ports: + console.print("Use --all-ports to include non-USB serial devices.") + return + table = Table(title="Serial Ports") + table.add_column("Port", no_wrap=True) + table.add_column("Description") + table.add_column("Manufacturer") + for port in sorted(ports, key=lambda info: info["device"]): + table.add_row( + Text(port["device"]), + Text(port["description"]), + Text(port["manufacturer"] or "Unknown"), + ) + console.print(table) + + def prepare_pairing_state( args: argparse.Namespace, console: Console, @@ -1665,6 +1697,9 @@ def main() -> None: parser = build_arg_parser() args = parser.parse_args() console = Console() + if args.list_ports: + list_serial_ports(console, args) + return config = build_bridge_config(console, args) initialize_sdl(parser) contexts: Dict[int, ControllerContext] = {}