Refactor
This commit is contained in:
parent
1cb7075180
commit
aef37123fd
4 changed files with 81 additions and 72 deletions
|
|
@ -992,6 +992,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||||
030000006d04000019c2000005030000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
030000006d04000019c2000005030000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||||
030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
||||||
030000006d04000018c2000000010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X,
|
030000006d04000018c2000000010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||||
|
030000006d04000019c2000000020000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||||
03000000380700005032000000010000,Mad Catz PS3 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
03000000380700005032000000010000,Mad Catz PS3 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||||
03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||||
03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
|
03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
|
||||||
|
|
@ -1153,6 +1154,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||||
030000005e040000130b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
030000005e040000130b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||||
030000005e040000130b000022050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
030000005e040000130b000022050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||||
030000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
030000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||||
|
030000005e040000220b000021050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||||
03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,
|
03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||||
03000000120c0000100e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
03000000120c0000100e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||||
03000000120c0000101e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
03000000120c0000101e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,6 @@ from pathlib import Path
|
||||||
from typing import Dict, List, Optional, Tuple
|
from typing import Dict, List, Optional, Tuple
|
||||||
|
|
||||||
from serial import SerialException
|
from serial import SerialException
|
||||||
from serial.tools import list_ports
|
|
||||||
from serial.tools import list_ports_common
|
|
||||||
|
|
||||||
import sdl2
|
import sdl2
|
||||||
import sdl2.ext
|
import sdl2.ext
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
|
|
@ -44,13 +41,14 @@ from switch_pico_uart import (
|
||||||
axis_to_stick,
|
axis_to_stick,
|
||||||
str_to_dpad,
|
str_to_dpad,
|
||||||
decode_rumble,
|
decode_rumble,
|
||||||
|
discover_serial_ports,
|
||||||
trigger_to_button,
|
trigger_to_button,
|
||||||
)
|
)
|
||||||
|
|
||||||
RUMBLE_IDLE_TIMEOUT = 0.25 # seconds without packets before forcing rumble off
|
RUMBLE_IDLE_TIMEOUT = 0.25 # seconds without packets before forcing rumble off
|
||||||
RUMBLE_STUCK_TIMEOUT = 0.60 # continuous same-energy rumble will be stopped after this
|
RUMBLE_STUCK_TIMEOUT = 0.60 # continuous same-energy rumble will be stopped after this
|
||||||
RUMBLE_MIN_ACTIVE = 0.50 # below this, rumble is treated as off/noise
|
RUMBLE_MIN_ACTIVE = 0.40 # below this, rumble is treated as off/noise
|
||||||
RUMBLE_SCALE = 0.8
|
RUMBLE_SCALE = 1.0
|
||||||
CONTROLLER_DB_URL_DEFAULT = (
|
CONTROLLER_DB_URL_DEFAULT = (
|
||||||
"https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt"
|
"https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt"
|
||||||
)
|
)
|
||||||
|
|
@ -145,66 +143,6 @@ STICK_AXIS_LABELS = (
|
||||||
STICK_AXES = tuple(axis for axis, _ in STICK_AXIS_LABELS)
|
STICK_AXES = tuple(axis for axis, _ in STICK_AXIS_LABELS)
|
||||||
|
|
||||||
|
|
||||||
def is_usb_serial(path: str) -> bool:
|
|
||||||
"""
|
|
||||||
Heuristic for USB serial path prefixes (best-effort when VID/PID are missing).
|
|
||||||
|
|
||||||
Accepts common USB-adapter patterns; rejects generic /dev/tty* unless they
|
|
||||||
clearly indicate USB.
|
|
||||||
"""
|
|
||||||
lower = path.lower()
|
|
||||||
usb_prefixes = (
|
|
||||||
"/dev/ttyusb", # Linux USB serial
|
|
||||||
"/dev/ttyacm", # Linux CDC ACM
|
|
||||||
"/dev/cu.usb", # macOS cu/tty USB adapters
|
|
||||||
"/dev/tty.usb",
|
|
||||||
)
|
|
||||||
if lower.startswith(usb_prefixes):
|
|
||||||
return True
|
|
||||||
# Default to False for unknown paths; caller can include_non_usb to override.
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def is_usb_serial_port(port: list_ports_common.ListPortInfo) -> bool:
|
|
||||||
"""Heuristic: prefer ports with USB VID/PID; fall back to path hints."""
|
|
||||||
if getattr(port, "vid", None) is not None or getattr(port, "pid", None) is not None:
|
|
||||||
return True
|
|
||||||
path = port.device or ""
|
|
||||||
manufacturer = (getattr(port, "manufacturer", "") or "").upper()
|
|
||||||
if "USB" in manufacturer:
|
|
||||||
return True
|
|
||||||
return is_usb_serial(path)
|
|
||||||
|
|
||||||
|
|
||||||
def discover_ports(
|
|
||||||
include_non_usb: bool = False,
|
|
||||||
ignore_descriptions: Optional[List[str]] = None,
|
|
||||||
include_descriptions: Optional[List[str]] = None,
|
|
||||||
) -> List[Dict[str, str]]:
|
|
||||||
"""List serial ports, optionally filtering by description and USB-ness."""
|
|
||||||
ignored = [d.lower() for d in ignore_descriptions or []]
|
|
||||||
includes = [d.lower() for d in include_descriptions or []]
|
|
||||||
results: List[Dict[str, str]] = []
|
|
||||||
for port in list_ports.comports():
|
|
||||||
path = port.device or ""
|
|
||||||
if not path:
|
|
||||||
continue
|
|
||||||
if not include_non_usb and not is_usb_serial_port(port):
|
|
||||||
continue
|
|
||||||
desc_lower = (port.description or "").lower()
|
|
||||||
if includes and not any(keep in desc_lower for keep in includes):
|
|
||||||
continue
|
|
||||||
if any(skip in desc_lower for skip in ignored):
|
|
||||||
continue
|
|
||||||
results.append(
|
|
||||||
{
|
|
||||||
"device": path,
|
|
||||||
"description": port.description or "Unknown",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return results
|
|
||||||
|
|
||||||
|
|
||||||
def interactive_pairing(
|
def interactive_pairing(
|
||||||
console: Console, controller_info: Dict[int, str], ports: List[Dict[str, str]]
|
console: Console, controller_info: Dict[int, str], ports: List[Dict[str, str]]
|
||||||
) -> List[Tuple[int, str]]:
|
) -> List[Tuple[int, str]]:
|
||||||
|
|
@ -867,7 +805,7 @@ def prepare_pairing_state(
|
||||||
if not controller_indices:
|
if not controller_indices:
|
||||||
parser.error("No controllers detected for interactive pairing.")
|
parser.error("No controllers detected for interactive pairing.")
|
||||||
# Interactive pairing shows the discovered ports and lets the user bind explicitly.
|
# Interactive pairing shows the discovered ports and lets the user bind explicitly.
|
||||||
discovered = discover_ports(
|
discovered = discover_serial_ports(
|
||||||
include_non_usb=include_non_usb,
|
include_non_usb=include_non_usb,
|
||||||
ignore_descriptions=ignore_port_desc,
|
ignore_descriptions=ignore_port_desc,
|
||||||
include_descriptions=include_port_desc,
|
include_descriptions=include_port_desc,
|
||||||
|
|
@ -883,7 +821,7 @@ def prepare_pairing_state(
|
||||||
console.print(f"[green]Prepared {len(available_ports)} specified UART port(s) for auto-pairing.[/green]")
|
console.print(f"[green]Prepared {len(available_ports)} specified UART port(s) for auto-pairing.[/green]")
|
||||||
else:
|
else:
|
||||||
# Passive mode: grab whatever UARTs exist now, and keep looking later.
|
# Passive mode: grab whatever UARTs exist now, and keep looking later.
|
||||||
discovered = discover_ports(
|
discovered = discover_serial_ports(
|
||||||
include_non_usb=include_non_usb,
|
include_non_usb=include_non_usb,
|
||||||
ignore_descriptions=ignore_port_desc,
|
ignore_descriptions=ignore_port_desc,
|
||||||
include_descriptions=include_port_desc,
|
include_descriptions=include_port_desc,
|
||||||
|
|
@ -960,7 +898,7 @@ def discover_new_ports(pairing: PairingState, contexts: Dict[int, ControllerCont
|
||||||
"""Scan for new serial ports and add unused ones to the available pool."""
|
"""Scan for new serial ports and add unused ones to the available pool."""
|
||||||
if not pairing.auto_discover_ports:
|
if not pairing.auto_discover_ports:
|
||||||
return
|
return
|
||||||
discovered = discover_ports(
|
discovered = discover_serial_ports(
|
||||||
include_non_usb=pairing.include_non_usb,
|
include_non_usb=pairing.include_non_usb,
|
||||||
ignore_descriptions=pairing.ignore_port_desc,
|
ignore_descriptions=pairing.ignore_port_desc,
|
||||||
include_descriptions=pairing.include_port_desc,
|
include_descriptions=pairing.include_port_desc,
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
# example_switch_macro.py
|
# example_switch_macro.py
|
||||||
import time
|
import time
|
||||||
from switch_pico_uart import SwitchUARTClient, SwitchButton, SwitchDpad
|
from switch_pico_uart import SwitchUARTClient, SwitchButton, SwitchDpad, first_serial_port
|
||||||
|
|
||||||
PORT = "COM5" # change to your serial port, e.g. /dev/cu.usbserial-0001
|
PORT = first_serial_port(include_descriptions=["USB to UART"]) or "COM5" # auto-pick first serial port, or fall back
|
||||||
SEND_INTERVAL = 1 / 500 # optional: match controller_uart_bridge default
|
SEND_INTERVAL = 1 / 500 # optional: match controller_uart_bridge default
|
||||||
|
|
||||||
# Convenience list of every SwitchButton (plus DPAD directions).
|
# Convenience list of every SwitchButton (plus DPAD directions).
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,10 @@ import time
|
||||||
import threading
|
import threading
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import IntEnum, IntFlag
|
from enum import IntEnum, IntFlag
|
||||||
from typing import Iterable, Mapping, Optional, Tuple, Union
|
from typing import Iterable, Mapping, Optional, Tuple, Union, List, Dict
|
||||||
|
|
||||||
import serial
|
import serial
|
||||||
|
from serial.tools import list_ports, list_ports_common
|
||||||
|
|
||||||
UART_HEADER = 0xAA
|
UART_HEADER = 0xAA
|
||||||
RUMBLE_HEADER = 0xBB
|
RUMBLE_HEADER = 0xBB
|
||||||
|
|
@ -57,6 +58,74 @@ class SwitchDpad(IntEnum):
|
||||||
CENTER = 0x08
|
CENTER = 0x08
|
||||||
|
|
||||||
|
|
||||||
|
def _is_usb_serial_path(path: str) -> bool:
|
||||||
|
"""Heuristic for USB serial path prefixes."""
|
||||||
|
lower = path.lower()
|
||||||
|
usb_prefixes = (
|
||||||
|
"/dev/ttyusb", # Linux USB serial
|
||||||
|
"/dev/ttyacm", # Linux CDC ACM
|
||||||
|
"/dev/cu.usb", # macOS cu/tty USB adapters
|
||||||
|
"/dev/tty.usb",
|
||||||
|
)
|
||||||
|
if lower.startswith(usb_prefixes):
|
||||||
|
return True
|
||||||
|
# Windows COM ports don't clearly indicate USB; treat as unknown here.
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _is_usb_serial_port(port: list_ports_common.ListPortInfo) -> bool:
|
||||||
|
"""Heuristic: prefer ports with USB VID/PID; fall back to path hints."""
|
||||||
|
if getattr(port, "vid", None) is not None or getattr(port, "pid", None) is not None:
|
||||||
|
return True
|
||||||
|
path = port.device or ""
|
||||||
|
manufacturer = (getattr(port, "manufacturer", "") or "").upper()
|
||||||
|
if "USB" in manufacturer:
|
||||||
|
return True
|
||||||
|
return _is_usb_serial_path(path)
|
||||||
|
|
||||||
|
|
||||||
|
def discover_serial_ports(
|
||||||
|
include_non_usb: bool = False,
|
||||||
|
ignore_descriptions: Optional[List[str]] = None,
|
||||||
|
include_descriptions: Optional[List[str]] = None,
|
||||||
|
) -> List[Dict[str, str]]:
|
||||||
|
"""
|
||||||
|
List serial ports with simple filtering similar to controller_uart_bridge.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
include_non_usb: Include ports that don't look USB-based (e.g., onboard UARTs).
|
||||||
|
ignore_descriptions: Substrings (case-insensitive) to exclude by description.
|
||||||
|
include_descriptions: If provided, only include ports whose description contains one of these substrings.
|
||||||
|
"""
|
||||||
|
ignored = [d.lower() for d in (ignore_descriptions or [])]
|
||||||
|
includes = [d.lower() for d in (include_descriptions or [])]
|
||||||
|
results: List[Dict[str, str]] = []
|
||||||
|
for port in list_ports.comports():
|
||||||
|
path = port.device or ""
|
||||||
|
if not path:
|
||||||
|
continue
|
||||||
|
if not include_non_usb and not _is_usb_serial_port(port):
|
||||||
|
continue
|
||||||
|
desc_lower = (port.description or "").lower()
|
||||||
|
if includes and not any(keep in desc_lower for keep in includes):
|
||||||
|
continue
|
||||||
|
if any(skip in desc_lower for skip in ignored):
|
||||||
|
continue
|
||||||
|
results.append({"device": path, "description": port.description or "Unknown"})
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def first_serial_port(
|
||||||
|
include_non_usb: bool = False,
|
||||||
|
ignore_descriptions: Optional[List[str]] = None,
|
||||||
|
include_descriptions: Optional[List[str]] = None,
|
||||||
|
) -> Optional[str]:
|
||||||
|
"""Return the first discovered serial port path (or None if none are found)."""
|
||||||
|
ports = discover_serial_ports(include_non_usb, ignore_descriptions, include_descriptions)
|
||||||
|
if not ports:
|
||||||
|
return None
|
||||||
|
return ports[0]["device"]
|
||||||
|
|
||||||
def clamp_byte(value: Union[int, float]) -> int:
|
def clamp_byte(value: Union[int, float]) -> int:
|
||||||
"""Clamp a numeric value to the 0-255 byte range."""
|
"""Clamp a numeric value to the 0-255 byte range."""
|
||||||
return max(0, min(255, int(value)))
|
return max(0, min(255, int(value)))
|
||||||
|
|
@ -90,7 +159,7 @@ def trigger_to_button(value: int, threshold: int) -> bool:
|
||||||
|
|
||||||
|
|
||||||
def str_to_dpad(flags: Mapping[str, bool]) -> SwitchDpad:
|
def str_to_dpad(flags: Mapping[str, bool]) -> SwitchDpad:
|
||||||
"""Translate DPAD button flags into a Switch hat value."""
|
"""Translate DPAD button flags into a Switch hat/DPAD value."""
|
||||||
up = flags.get("up", False)
|
up = flags.get("up", False)
|
||||||
down = flags.get("down", False)
|
down = flags.get("down", False)
|
||||||
left = flags.get("left", False)
|
left = flags.get("left", False)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue