Context
I embed pyOCD as a library in an application that turns connection failures into actionable messages for end users, so I need to tell ST-Link failures apart programmatically.
Current behaviour
STLink._check_status() reads the numeric firmware status, formats it into the message via Status.get_error_message(), and does not carry the number any further:
status, = struct.unpack('<H', response)
if status != Status.JTAG_OK:
error_message = Status.get_error_message(status)
if status in self._ERROR_CLASSES:
raise self._ERROR_CLASSES[status](error_message)
else:
raise exceptions.ProbeError(error_message)
The split in _ERROR_CLASSES reads as deliberate to me: the statuses mapped there are the SWD_* transfer errors, which have transport-agnostic equivalents in pyOCD's exception hierarchy, while the ST-Link firmware statuses (JTAG_*, BAD_AP, SWV_NOT_AVAILABLE) have no generic counterpart. I'm not suggesting that should change.
The consequence for a caller is that for those vendor-specific statuses the number is the only thing that distinguishes them, and it is currently present only inside the message text. These four all arrive as a bare ProbeError, but need different remedies:
| status |
message |
remedy we show |
| 4, 5, 9 |
Unknown JTAG chain / No device connected / Get IDCODE error |
check wiring and target power |
| 11 |
Debug power error |
check target supply |
| 14 |
Already opened in another mode |
close the other debugger |
| 65 |
Frequency not supported |
lower the configured clock |
Today we recover the number with a regex over the message. That works, but the message is composed rather than fixed in at least one path — TransferFaultError renders as Memory transfer fault (STLink error (17): AP fault) — so it seems a fragile thing to depend on.
Reproduction (no hardware)
from pyocd.probe.stlink.stlink import STLink
from pyocd.probe.stlink.constants import Status
from pyocd.core import exceptions
for status in (0x04, 0x0B, 0x0E, 0x41):
cls = STLink._ERROR_CLASSES.get(status, exceptions.ProbeError)
print(cls(Status.get_error_message(status)))
Checked on 0.45.1; stlink/constants.py and core/exceptions.py are unchanged since 0.37.0.
Suggestion
Carry the status on the exception, the way pyOCD already carries structured error data elsewhere (TransferFaultError.fault_address, FlashFailure.result_code): an optional status keyword on ProbeError, defaulting to None, passed from _check_status(). That leaves the message format and _ERROR_CLASSES untouched and is a no-op for callers that ignore it.
Would you take a PR against develop for this? Happy to hang it off a different exception class if ProbeError isn't the right place.
Context
I embed pyOCD as a library in an application that turns connection failures into actionable messages for end users, so I need to tell ST-Link failures apart programmatically.
Current behaviour
STLink._check_status()reads the numeric firmware status, formats it into the message viaStatus.get_error_message(), and does not carry the number any further:The split in
_ERROR_CLASSESreads as deliberate to me: the statuses mapped there are theSWD_*transfer errors, which have transport-agnostic equivalents in pyOCD's exception hierarchy, while the ST-Link firmware statuses (JTAG_*,BAD_AP,SWV_NOT_AVAILABLE) have no generic counterpart. I'm not suggesting that should change.The consequence for a caller is that for those vendor-specific statuses the number is the only thing that distinguishes them, and it is currently present only inside the message text. These four all arrive as a bare
ProbeError, but need different remedies:Today we recover the number with a regex over the message. That works, but the message is composed rather than fixed in at least one path —
TransferFaultErrorrenders asMemory transfer fault (STLink error (17): AP fault)— so it seems a fragile thing to depend on.Reproduction (no hardware)
Checked on 0.45.1;
stlink/constants.pyandcore/exceptions.pyare unchanged since 0.37.0.Suggestion
Carry the status on the exception, the way pyOCD already carries structured error data elsewhere (
TransferFaultError.fault_address,FlashFailure.result_code): an optionalstatuskeyword onProbeError, defaulting toNone, passed from_check_status(). That leaves the message format and_ERROR_CLASSESuntouched and is a no-op for callers that ignore it.Would you take a PR against
developfor this? Happy to hang it off a different exception class ifProbeErrorisn't the right place.