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>`_) * 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>`__ * 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>`_) * 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 * 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>`__ 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 * 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 import fs, proc, util
from platformio.compat import string_types from platformio.compat import string_types
from platformio.debug.exception import DebugInvalidOptionsError 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.config import ProjectConfig
from platformio.project.helpers import load_build_metadata from platformio.project.helpers import load_build_metadata
from platformio.project.options import ProjectOptions from platformio.project.options import ProjectOptions
@ -119,12 +119,22 @@ class DebugConfigBase: # pylint: disable=too-many-instance-attributes
@property @property
def port(self): def port(self):
return reveal_debug_port( initial_port = (
self.env_options.get("debug_port", self.tool_settings.get("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_name,
self.tool_settings, 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 @port.setter
def port(self, value): def port(self, value):

View File

@ -16,14 +16,12 @@ import os
import re import re
import sys import sys
import time import time
from fnmatch import fnmatch
from hashlib import sha1 from hashlib import sha1
from io import BytesIO from io import BytesIO
from platformio.cli import PlatformioCLI 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.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 cli as cmd_run
from platformio.run.cli import print_processing_header from platformio.run.cli import print_processing_header
from platformio.test.helpers import list_test_names 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: with open(prog_hash_path, mode="w", encoding="utf8") as fp:
fp.write(new_digest) fp.write(new_digest)
return True 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 click
import serial 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.device.list.util import list_logical_devices, list_serial_ports
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
KNOWN_UART_HWIDS = ( BLACK_MAGIC_HWIDS = [
"1D50:6018",
]
KNOWN_UART_HWIDS = BLACK_MAGIC_HWIDS + [
# Silicon Labs # Silicon Labs
"10C4:EA60", # CP210X "10C4:EA60", # CP210X
"10C4:EA61", # CP210X "10C4:EA61", # CP210X
@ -33,7 +36,7 @@ KNOWN_UART_HWIDS = (
"10C4:EA71", # CP2108 "10C4:EA71", # CP2108
"10C4:EA80", # CP2110 "10C4:EA80", # CP2110
"10C4:80A9", # CP210X "10C4:80A9", # CP210X
) ]
def normalize_board_hwid(value): def normalize_board_hwid(value):
@ -91,18 +94,44 @@ def find_serial_port(
return best_port or 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: try:
@retry(timeout=timeout) @retry(timeout=timeout)
def wrapper(): def wrapper():
for item in list_serial_ports(): candidates = []
port = item["port"] for item in list_serial_ports(filter_hwid=True):
if IS_WINDOWS and port.startswith("COM") and len(port) > 4: if (
port = "\\\\.\\%s" % port not any(hwid in item["hwid"].upper() for hwid in BLACK_MAGIC_HWIDS)
if "GDB" in item["description"]: and not "Black Magic" in item["description"]
return port ):
raise retry.RetryNextException() 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() return wrapper()
except retry.RetryStopException: 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): if item["name"] and any(l in item["name"].lower() for l in msdlabels):
return item["path"] return item["path"]
return None 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