mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-31 18:44:27 +02:00
Handle UDEV rules and their PID/VID data when searching for serial port
This commit is contained in:
@@ -20,6 +20,7 @@ import serial
|
|||||||
|
|
||||||
from platformio.compat import IS_MACOS, IS_WINDOWS
|
from platformio.compat import IS_MACOS, IS_WINDOWS
|
||||||
from platformio.device.list.util import list_logical_devices, list_serial_ports
|
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.package.manager.platform import PlatformPackageManager
|
||||||
from platformio.platform.factory import PlatformFactory
|
from platformio.platform.factory import PlatformFactory
|
||||||
from platformio.util import retry
|
from platformio.util import retry
|
||||||
@@ -27,16 +28,29 @@ from platformio.util import retry
|
|||||||
BLACK_MAGIC_HWIDS = [
|
BLACK_MAGIC_HWIDS = [
|
||||||
"1D50:6018",
|
"1D50:6018",
|
||||||
]
|
]
|
||||||
KNOWN_UART_HWIDS = BLACK_MAGIC_HWIDS + [
|
|
||||||
# Silicon Labs
|
|
||||||
"10C4:EA60", # CP210X
|
def parse_udev_rules_hwids(path):
|
||||||
"10C4:EA61", # CP210X
|
result = []
|
||||||
"10C4:EA63", # CP210X
|
with open(path, mode="r", encoding="utf8") as fp:
|
||||||
"10C4:EA70", # CP2105
|
for line in fp.readlines():
|
||||||
"10C4:EA71", # CP2108
|
line = line.strip()
|
||||||
"10C4:EA80", # CP2110
|
if not line or line.startswith("#"):
|
||||||
"10C4:80A9", # CP210X
|
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):
|
def normalize_board_hwid(value):
|
||||||
@@ -73,7 +87,7 @@ def find_serial_port( # pylint: disable=too-many-arguments
|
|||||||
upload_protocol=None,
|
upload_protocol=None,
|
||||||
ensure_ready=False,
|
ensure_ready=False,
|
||||||
prefer_gdb_port=False,
|
prefer_gdb_port=False,
|
||||||
timeout=3,
|
timeout=2,
|
||||||
):
|
):
|
||||||
if initial_port:
|
if initial_port:
|
||||||
if not is_pattern_port(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):
|
def find_known_uart_port(ensure_ready=False, timeout=0):
|
||||||
known_hwids = list(KNOWN_UART_HWIDS)
|
known_hwids = list(BLACK_MAGIC_HWIDS)
|
||||||
# load HWIDs from installed dev-platforms
|
|
||||||
|
# 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():
|
for platform in PlatformPackageManager().get_installed():
|
||||||
p = PlatformFactory.new(platform)
|
p = PlatformFactory.new(platform)
|
||||||
for board_config in p.get_boards().values():
|
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)
|
@retry(timeout=timeout)
|
||||||
def wrapper():
|
def wrapper():
|
||||||
for item in list_serial_ports(filter_hwid=True):
|
for item in list_serial_ports(as_objects=True):
|
||||||
port = item["port"]
|
if not item.vid or not item.pid:
|
||||||
hwid = item["hwid"].upper()
|
|
||||||
if not any(item in hwid for item in known_hwids):
|
|
||||||
continue
|
continue
|
||||||
if not ensure_ready or is_serial_port_ready(port):
|
hwid = "{:04X}:{:04X}".format(item.vid, item.pid)
|
||||||
return port
|
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()
|
raise retry.RetryNextException()
|
||||||
|
|
||||||
return wrapper()
|
return wrapper()
|
||||||
|
@@ -24,13 +24,16 @@ from platformio import __version__, exception, proc
|
|||||||
from platformio.compat import IS_MACOS, IS_WINDOWS
|
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:
|
try:
|
||||||
# pylint: disable=import-outside-toplevel
|
# pylint: disable=import-outside-toplevel
|
||||||
from serial.tools.list_ports import comports
|
from serial.tools.list_ports import comports
|
||||||
except ImportError:
|
except ImportError:
|
||||||
raise exception.GetSerialPortsError(os.name)
|
raise exception.GetSerialPortsError(os.name)
|
||||||
|
|
||||||
|
if as_objects:
|
||||||
|
return comports()
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
for p, d, h in comports():
|
for p, d, h in comports():
|
||||||
if not p:
|
if not p:
|
||||||
|
@@ -97,6 +97,12 @@ def calculate_folder_size(path):
|
|||||||
return result
|
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():
|
def ensure_udev_rules():
|
||||||
from platformio.util import get_systype # pylint: disable=import-outside-toplevel
|
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):
|
if not any(os.path.isfile(p) for p in installed_rules):
|
||||||
raise exception.MissedUdevRules
|
raise exception.MissedUdevRules
|
||||||
|
|
||||||
origin_path = os.path.abspath(
|
origin_path = get_platformio_udev_rules_path()
|
||||||
os.path.join(get_source_dir(), "..", "scripts", "99-platformio-udev.rules")
|
|
||||||
)
|
|
||||||
if not os.path.isfile(origin_path):
|
if not os.path.isfile(origin_path):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user