Improved a serial port finder for Black Magic Probe // Resolve #4023

This commit is contained in:
Ivan Kravets
2022-06-17 23:05:20 +03:00
parent f68c18d1e5
commit b72c1636f7
4 changed files with 67 additions and 58 deletions

View File

@ -33,6 +33,7 @@ PlatformIO Core 6
* Documented `Stringification <https://docs.platformio.org/en/latest/projectconf/section_env_build.html#stringification>`__ converting a macro argument into a string constant (`issue #4310 <https://github.com/platformio/platformio-core/issues/4310>`_)
* Added ``env.StringifyMacro(value)`` helper function for the `Advanced Scripting <https://docs.platformio.org/en/latest/scripting/index.html>`__
* Allowed to ``Import("projenv")`` in a library extra script (`issue #4305 <https://github.com/platformio/platformio-core/issues/4305>`_)
* Improved a serial port finder for `Black Magic Probe <https://docs.platformio.org/en/latest/plus/debug-tools/blackmagic.html>`__ (`issue #4023 <https://github.com/platformio/platformio-core/issues/4023>`_)
* Improved a serial port finder for a board with predefined HWIDs
* Fixed an issue when the `build_unflags <https://docs.platformio.org/en/latest/projectconf/section_env_build.html#build-unflags>`__ operation ignores a flag value (`issue #4309 <https://github.com/platformio/platformio-core/issues/4309>`_)
* Fixed an issue when the `build_unflags <https://docs.platformio.org/en/latest/projectconf/section_env_build.html#build-unflags>`__ option was not applied to the ``ASPPFLAGS`` scope

View File

@ -18,7 +18,7 @@ import os
from platformio import fs, proc, util
from platformio.compat import string_types
from platformio.debug.exception import DebugInvalidOptionsError
from platformio.debug.helpers import reveal_debug_port
from platformio.device.finder import find_debug_port
from platformio.project.config import ProjectConfig
from platformio.project.helpers import load_build_metadata
from platformio.project.options import ProjectOptions
@ -119,12 +119,22 @@ class DebugConfigBase: # pylint: disable=too-many-instance-attributes
@property
def port(self):
return reveal_debug_port(
initial_port = (
self.env_options.get("debug_port", self.tool_settings.get("port"))
or self._port,
or self._port
)
port = find_debug_port(
initial_port,
self.tool_name,
self.tool_settings,
)
if port:
return port
if not self.tool_settings.get("require_debug_port"):
return None
raise DebugInvalidOptionsError(
"Please specify `debug_port` for the working environment"
)
@port.setter
def port(self, value):

View File

@ -16,14 +16,12 @@ import os
import re
import sys
import time
from fnmatch import fnmatch
from hashlib import sha1
from io import BytesIO
from platformio.cli import PlatformioCLI
from platformio.compat import IS_WINDOWS, is_bytes
from platformio.compat import is_bytes
from platformio.debug.exception import DebugInvalidOptionsError
from platformio.device.list.util import list_serial_ports
from platformio.run.cli import cli as cmd_run
from platformio.run.cli import print_processing_header
from platformio.test.helpers import list_test_names
@ -161,44 +159,3 @@ def is_prog_obsolete(prog_path):
with open(prog_hash_path, mode="w", encoding="utf8") as fp:
fp.write(new_digest)
return True
def reveal_debug_port(env_debug_port, tool_name, tool_settings):
def _get_pattern():
if not env_debug_port:
return None
if set(["*", "?", "[", "]"]) & set(env_debug_port):
return env_debug_port
return None
def _is_match_pattern(port):
pattern = _get_pattern()
if not pattern:
return True
return fnmatch(port, pattern)
def _look_for_serial_port(hwids):
for item in list_serial_ports(filter_hwid=True):
if not _is_match_pattern(item["port"]):
continue
port = item["port"]
if tool_name.startswith("blackmagic"):
if IS_WINDOWS and port.startswith("COM") and len(port) > 4:
port = "\\\\.\\%s" % port
if "GDB" in item["description"]:
return port
for hwid in hwids:
hwid_str = ("%s:%s" % (hwid[0], hwid[1])).replace("0x", "")
if hwid_str in item["hwid"]:
return port
return None
if env_debug_port and not _get_pattern():
return env_debug_port
if not tool_settings.get("require_debug_port"):
return None
debug_port = _look_for_serial_port(tool_settings.get("hwids", []))
if not debug_port:
raise DebugInvalidOptionsError("Please specify `debug_port` for environment")
return debug_port

View File

@ -18,13 +18,16 @@ from fnmatch import fnmatch
import click
import serial
from platformio.compat import IS_WINDOWS
from platformio.compat import IS_MACOS, IS_WINDOWS
from platformio.device.list.util import list_logical_devices, list_serial_ports
from platformio.package.manager.platform import PlatformPackageManager
from platformio.platform.factory import PlatformFactory
from platformio.util import retry
KNOWN_UART_HWIDS = (
BLACK_MAGIC_HWIDS = [
"1D50:6018",
]
KNOWN_UART_HWIDS = BLACK_MAGIC_HWIDS + [
# Silicon Labs
"10C4:EA60", # CP210X
"10C4:EA61", # CP210X
@ -33,7 +36,7 @@ KNOWN_UART_HWIDS = (
"10C4:EA71", # CP2108
"10C4:EA80", # CP2110
"10C4:80A9", # CP210X
)
]
def normalize_board_hwid(value):
@ -91,18 +94,44 @@ def find_serial_port(
return best_port or port
def find_blackmagic_serial_port(timeout=0):
def find_blackmagic_serial_port(timeout=0, only_gdb_port=False):
try:
@retry(timeout=timeout)
def wrapper():
for item in list_serial_ports():
port = item["port"]
if IS_WINDOWS and port.startswith("COM") and len(port) > 4:
port = "\\\\.\\%s" % port
if "GDB" in item["description"]:
return port
raise retry.RetryNextException()
candidates = []
for item in list_serial_ports(filter_hwid=True):
if (
not any(hwid in item["hwid"].upper() for hwid in BLACK_MAGIC_HWIDS)
and not "Black Magic" in item["description"]
):
continue
if (
IS_WINDOWS
and item["port"].startswith("COM")
and len(item["port"]) > 4
):
item["port"] = "\\\\.\\%s" % item["port"]
candidates.append(item)
if not candidates:
raise retry.RetryNextException()
for item in candidates:
if ("GDB" if only_gdb_port else "UART") in item["description"]:
return item["port"]
if IS_MACOS:
# 1 - GDB, 3 - UART
for item in candidates:
if item["port"].endswith("1" if only_gdb_port else "3"):
return item["port"]
candidates = sorted(candidates, key=lambda item: item["port"])
return (
candidates[0] # first port is GDB?
if len(candidates) == 1 or only_gdb_port
else candidates[1]
)["port"]
return wrapper()
except retry.RetryStopException:
@ -193,3 +222,15 @@ def find_mbed_disk(initial_port):
if item["name"] and any(l in item["name"].lower() for l in msdlabels):
return item["path"]
return None
def find_debug_port(initial_port, tool_name, tool_settings):
if initial_port:
if not is_pattern_port(initial_port):
return initial_port
return match_serial_port(initial_port)
if not tool_settings.get("require_debug_port"):
return None
if tool_name.startswith("blackmagic"):
return find_blackmagic_serial_port(timeout=0, only_gdb_port=True)
return None