Handle UDEV rules and their PID/VID data when searching for serial port

This commit is contained in:
Ivan Kravets
2022-06-20 22:21:28 +03:00
parent 4b2f0eb1d5
commit 92a5c1bac6
3 changed files with 52 additions and 23 deletions

View File

@ -20,6 +20,7 @@ import serial
from platformio.compat import IS_MACOS, IS_WINDOWS
from platformio.device.list.util import list_logical_devices, list_serial_ports
from platformio.fs import get_platformio_udev_rules_path
from platformio.package.manager.platform import PlatformPackageManager
from platformio.platform.factory import PlatformFactory
from platformio.util import retry
@ -27,16 +28,29 @@ from platformio.util import retry
BLACK_MAGIC_HWIDS = [
"1D50:6018",
]
KNOWN_UART_HWIDS = BLACK_MAGIC_HWIDS + [
# Silicon Labs
"10C4:EA60", # CP210X
"10C4:EA61", # CP210X
"10C4:EA63", # CP210X
"10C4:EA70", # CP2105
"10C4:EA71", # CP2108
"10C4:EA80", # CP2110
"10C4:80A9", # CP210X
]
def parse_udev_rules_hwids(path):
result = []
with open(path, mode="r", encoding="utf8") as fp:
for line in fp.readlines():
line = line.strip()
if not line or line.startswith("#"):
continue
attrs = {}
for attr in line.split(","):
attr = attr.replace("==", "=").replace('"', "").strip()
if "=" not in attr:
continue
name, value = attr.split("=", 1)
attrs[name] = value
hwid = "%s:%s" % (
attrs.get("ATTRS{idVendor}", "*"),
attrs.get("ATTRS{idProduct}", "*"),
)
if hwid != "*:*":
result.append(hwid.upper())
return result
def normalize_board_hwid(value):
@ -73,7 +87,7 @@ def find_serial_port( # pylint: disable=too-many-arguments
upload_protocol=None,
ensure_ready=False,
prefer_gdb_port=False,
timeout=3,
timeout=2,
):
if initial_port:
if not is_pattern_port(initial_port):
@ -173,8 +187,14 @@ def find_board_serial_port(board_config, timeout=0):
def find_known_uart_port(ensure_ready=False, timeout=0):
known_hwids = list(KNOWN_UART_HWIDS)
# load HWIDs from installed dev-platforms
known_hwids = list(BLACK_MAGIC_HWIDS)
# load from UDEV rules
udev_rules_path = get_platformio_udev_rules_path()
if os.path.isfile(udev_rules_path):
known_hwids.extend(parse_udev_rules_hwids(udev_rules_path))
# load from installed dev-platforms
for platform in PlatformPackageManager().get_installed():
p = PlatformFactory.new(platform)
for board_config in p.get_boards().values():
@ -187,13 +207,15 @@ def find_known_uart_port(ensure_ready=False, timeout=0):
@retry(timeout=timeout)
def wrapper():
for item in list_serial_ports(filter_hwid=True):
port = item["port"]
hwid = item["hwid"].upper()
if not any(item in hwid for item in known_hwids):
for item in list_serial_ports(as_objects=True):
if not item.vid or not item.pid:
continue
if not ensure_ready or is_serial_port_ready(port):
return port
hwid = "{:04X}:{:04X}".format(item.vid, item.pid)
for pattern in known_hwids:
if fnmatch(hwid, pattern) and (
not ensure_ready or is_serial_port_ready(item.device)
):
return item.device
raise retry.RetryNextException()
return wrapper()

View File

@ -24,13 +24,16 @@ from platformio import __version__, exception, proc
from platformio.compat import IS_MACOS, IS_WINDOWS
def list_serial_ports(filter_hwid=False):
def list_serial_ports(filter_hwid=False, as_objects=False):
try:
# pylint: disable=import-outside-toplevel
from serial.tools.list_ports import comports
except ImportError:
raise exception.GetSerialPortsError(os.name)
if as_objects:
return comports()
result = []
for p, d, h in comports():
if not p:

View File

@ -97,6 +97,12 @@ def calculate_folder_size(path):
return result
def get_platformio_udev_rules_path():
return os.path.abspath(
os.path.join(get_source_dir(), "..", "scripts", "99-platformio-udev.rules")
)
def ensure_udev_rules():
from platformio.util import get_systype # pylint: disable=import-outside-toplevel
@ -119,9 +125,7 @@ def ensure_udev_rules():
if not any(os.path.isfile(p) for p in installed_rules):
raise exception.MissedUdevRules
origin_path = os.path.abspath(
os.path.join(get_source_dir(), "..", "scripts", "99-platformio-udev.rules")
)
origin_path = get_platformio_udev_rules_path()
if not os.path.isfile(origin_path):
return None