Add UART bridge serial port listing option

This commit is contained in:
Joey Yakimowich-Payne 2026-09-19 22:04:42 -06:00
commit 57c0b3606b
2 changed files with 42 additions and 0 deletions

View file

@ -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) ### 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. 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)**: - **macOS/Linux (terminal)**:
- Quick list with descriptions: `python -m serial.tools.list_ports -v` - 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` - 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`). - `--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. - `--ports PORTS...` or `--interactive` for auto/interactive pairing.
- `--all-ports` to include non-USB serial devices in discovery. - `--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). - `--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). - `--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). - `--list-controllers` to print detected controllers and their GUIDs, then exit (useful for GUID-based options).

View file

@ -32,6 +32,7 @@ import sdl3
from rich.console import Console from rich.console import Console
from rich.prompt import Prompt from rich.prompt import Prompt
from rich.table import Table from rich.table import Table
from rich.text import Text
from .switch_pico_uart import ( from .switch_pico_uart import (
UART_BAUD, UART_BAUD,
@ -641,6 +642,11 @@ def build_arg_parser() -> argparse.ArgumentParser:
action="store_true", action="store_true",
help="Include non-USB serial ports when listing devices.", 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( parser.add_argument(
"--frequency", "--frequency",
type=float, type=float,
@ -1002,6 +1008,32 @@ def list_controllers_with_guids(
console.print(table) 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( def prepare_pairing_state(
args: argparse.Namespace, args: argparse.Namespace,
console: Console, console: Console,
@ -1665,6 +1697,9 @@ def main() -> None:
parser = build_arg_parser() parser = build_arg_parser()
args = parser.parse_args() args = parser.parse_args()
console = Console() console = Console()
if args.list_ports:
list_serial_ports(console, args)
return
config = build_bridge_config(console, args) config = build_bridge_config(console, args)
initialize_sdl(parser) initialize_sdl(parser)
contexts: Dict[int, ControllerContext] = {} contexts: Dict[int, ControllerContext] = {}