diff --git a/pyocd/core/session.py b/pyocd/core/session.py index 5cca90de9..b3662c89c 100644 --- a/pyocd/core/session.py +++ b/pyocd/core/session.py @@ -132,6 +132,7 @@ def __init__( auto_open: bool = True, options: Optional[Mapping[str, Any]] = None, option_defaults: Optional[Mapping[str, Any]] = None, + command: Optional[str] = None, **kwargs ) -> None: """@brief Session constructor. @@ -166,6 +167,7 @@ def __init__( self._probe = probe self._closed: bool = True self._inited: bool = False + self._command = command self._user_script_namespace: Dict[str, Any] = {} self._user_script_proxy: Optional[UserScriptDelegateProxy] = None self._user_script_print_proxy = PrintProxy() @@ -331,6 +333,11 @@ def probe(self) -> Optional[DebugProbe]: """@brief The @ref pyocd.probe.debug_probe.DebugProbe "DebugProbe" instance.""" return self._probe + @property + def command(self) -> Optional[str]: + """@brief The current command being executed in the session.""" + return self._command + @property def board(self) -> Optional[Board]: """@brief The @ref pyocd.board.board.Board "Board" object.""" diff --git a/pyocd/subcommands/erase_cmd.py b/pyocd/subcommands/erase_cmd.py index 146a17275..6e3a6131b 100644 --- a/pyocd/subcommands/erase_cmd.py +++ b/pyocd/subcommands/erase_cmd.py @@ -87,6 +87,7 @@ def invoke(self) -> int: frequency=self._args.frequency, blocking=(not self._args.no_wait), connect_mode=self._args.connect_mode, + command=self._args.cmd, options=convert_session_options(self._args.options), option_defaults=self._modified_option_defaults(), ) diff --git a/pyocd/subcommands/load_cmd.py b/pyocd/subcommands/load_cmd.py index 567a10062..87170b3a5 100644 --- a/pyocd/subcommands/load_cmd.py +++ b/pyocd/subcommands/load_cmd.py @@ -98,6 +98,7 @@ def invoke(self) -> int: frequency=self._args.frequency, blocking=(not self._args.no_wait), connect_mode=self._args.connect_mode, + command=self._args.cmd, options=convert_session_options(self._args.options), option_defaults=self._modified_option_defaults(), ) diff --git a/pyocd/subcommands/reset_cmd.py b/pyocd/subcommands/reset_cmd.py index 07d969599..39c6502d8 100644 --- a/pyocd/subcommands/reset_cmd.py +++ b/pyocd/subcommands/reset_cmd.py @@ -86,6 +86,7 @@ def invoke(self) -> None: connect_mode=self._args.connect_mode, resume_on_disconnect=not self._args.halt, reset_type=self._args.reset_type, + command=self._args.cmd, options=convert_session_options(self._args.options), option_defaults=self._modified_option_defaults(), ) diff --git a/pyocd/target/pack/cbuild_run.py b/pyocd/target/pack/cbuild_run.py index b0b6ad708..1d418dbb3 100644 --- a/pyocd/target/pack/cbuild_run.py +++ b/pyocd/target/pack/cbuild_run.py @@ -95,7 +95,10 @@ def _cbuild_target_init(self, session: Session) -> None: super(self.__class__, self).__init__(session, self._cbuild_device.memory_map) self.vendor = self._cbuild_device.vendor self.part_number = self._cbuild_device.target - self._svd_location = SVDFile(filename=self._cbuild_device.svd) + if session.command not in ('load', 'erase', 'reset'): + # SVD file is not required for load/erase/reset commands + _svd = self._cbuild_device.svd + self._svd_location = SVDFile(filename=_svd) if _svd else None self.debug_sequence_delegate = CbuildRunDebugSequenceDelegate(self, self._cbuild_device) @staticmethod @@ -277,11 +280,11 @@ def _pack_path(cmsis_pack: str) -> Optional[Path]: if pack is not None: self._required_packs[pack] = _pack_path(pack) - def _check_path(self, file_path: Path) -> Path: - """@brief Checks if the required CMSIS pack is installed.""" + def _check_path(self, file_path: Path, required: bool = False) -> Path: + """@brief Checks if the required files are accessible and verifies pack installation if needed.""" file_path = Path(os.path.expandvars(str(file_path))).expanduser().resolve() - # If the path exists, we don't need to do any further checks - if file_path.exists(): + # If the file exists, we don't need to do any further checks + if file_path.is_file(): return file_path def _is_under(parent: Path, child: Path) -> bool: @@ -291,20 +294,28 @@ def _is_under(parent: Path, child: Path) -> bool: except ValueError: return False - self._get_required_packs() + # Select appropriate logging level and error message based on whether the file is required + if required: + log = LOG.error + err = f"File '{file_path}' is required but not found" + else: + log = LOG.warning + err = f"File '{file_path}' not found" + self._get_required_packs() # Verify pack installation only if the file is located within a required pack. for pack, pack_path in self._required_packs.items(): if pack_path is not None and _is_under(pack_path, file_path): if not pack_path.exists(): - raise CbuildRunError(f"Pack '{pack}' is required but not installed. " - f"Install with: cpackget add {pack}") - elif not file_path.exists(): - raise CbuildRunError(f"Installed pack '{pack}' is corrupted or incomplete. " - f"Reinstall with: cpackget add -F {pack}") + log("Pack '%s' is required but not installed. " + "Install with: cpackget add %s", pack, pack) + else: + log("Installed pack '%s' is corrupted or incomplete. " + "Reinstall with: cpackget add -F %s", pack, pack) + # We've found the relevant pack, no need to check further + break - # If we reach here, the file was not found and is not under any required pack. - raise CbuildRunError(f"File '{file_path}' is required but not found") + raise CbuildRunError(err) @property def target(self) -> str: @@ -354,19 +365,19 @@ def memory_map(self) -> MemoryMap: return self._memory_map @property - def svd(self) -> Optional[IO[bytes]]: - """@brief File-like object for the device's SVD file.""" + def svd(self) -> Optional[str]: + """@brief Path to the SVD file for the target device.""" #TODO handle multicore devices try: for desc in self.system_descriptions: if desc['type'] == 'svd': svd_path = self._check_path(Path(desc['file'])) LOG.debug("SVD path: %s", svd_path) - return io.BytesIO(svd_path.read_bytes()) + return str(svd_path) except CbuildRunError as err: - LOG.error("SVD file error: %s", err) + LOG.warning("SVD file error: %s", err) except (KeyError, IndexError): - LOG.error("Could not locate SVD in cbuild-run system-descriptions.") + LOG.warning("Could not locate SVD in cbuild-run system-descriptions.") return None @property @@ -683,7 +694,7 @@ def _memory_slice(memory: dict, start: int, size: int) -> None: flash_attrs['_RAMsize'] = algorithm['ram-size'] if ('_RAMstart' not in flash_attrs) or ('_RAMsize' not in flash_attrs): LOG.error("Flash algorithm '%s' has no RAMstart or RAMsize", algorithm['algorithm']) - algorithm_path = self._check_path(Path(algorithm['algorithm'])) + algorithm_path = self._check_path(Path(algorithm['algorithm']), required=True) flash_attrs['flm'] = PackFlashAlgo(str(algorithm_path)) # Set sector size to a fixed value to prevent any possibility of infinite recursion due to # the default lambdas for sector_size and blocksize returning each other's value. diff --git a/pyocd/target/pack/cmsis_pack.py b/pyocd/target/pack/cmsis_pack.py index f0e822a03..59700b5dc 100644 --- a/pyocd/target/pack/cmsis_pack.py +++ b/pyocd/target/pack/cmsis_pack.py @@ -1025,8 +1025,11 @@ def svd(self) -> Optional[IO[bytes]]: try: svdPath = self._info.debugs[0].attrib['svd'] return self.get_file(svdPath) + except FileNotFoundError as err: + LOG.error("SVD file error: %s", err) except (KeyError, IndexError): - return None + LOG.error("Could not locate SVD in CMSIS-Pack.") + return None @property def sequences(self) -> Set[DebugSequence]: @@ -1287,4 +1290,3 @@ def _build_aps_map(self) -> None: def __repr__(self): return "<%s@%x %s>" % (self.__class__.__name__, id(self), self.part_number) - diff --git a/pyocd/target/pack/pack_target.py b/pyocd/target/pack/pack_target.py index f14ee1c42..90b27dffc 100644 --- a/pyocd/target/pack/pack_target.py +++ b/pyocd/target/pack/pack_target.py @@ -386,7 +386,8 @@ def _pack_target__init__(self, session: Session) -> None: # type:ignore self.part_families = self._pack_device.families self.part_number = self._pack_device.part_number - self._svd_location = SVDFile(filename=self._pack_device.svd) + _svd = self._pack_device.svd + self._svd_location = SVDFile(filename=_svd) if _svd else None self.debug_sequence_delegate = PackDebugSequenceDelegate(self, self._pack_device)