Skip to content

Commit 5a52ccc

Browse files
authored
Merge pull request #997 from flit/bugfix/jlink_open
Fix issue when another process has a J-Link open
2 parents cbf3519 + be6b6ec commit 5a52ccc

File tree

4 files changed

+68
-24
lines changed

4 files changed

+68
-24
lines changed

pyocd/commands/commander.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ class PyOCDCommander(object):
3535
3636
Responsible for connecting the execution context, REPL, and commands, and handles connection.
3737
38+
Exit codes:
39+
- 0 = no errors
40+
- 1 = command error
41+
- 2 = transfer error
42+
- 3 = failed to create session (probe might not exist)
43+
- 4 = failed to open probe
44+
3845
@todo Replace use of args from argparse with something cleaner.
3946
"""
4047

@@ -169,7 +176,9 @@ def connect(self):
169176
self.exit_code = 3
170177
return False
171178

172-
self._post_connect()
179+
if not self._post_connect():
180+
self.exit_code = 4
181+
return False
173182

174183
result = self.context.attach_session(self.session)
175184
if not result:

pyocd/probe/aggregator.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ def get_all_connected_probes(unique_id=None):
5151
klasses, unique_id, is_explicit = DebugProbeAggregator._get_probe_classes(unique_id)
5252

5353
probes = []
54+
55+
# First look for a match against the full ID, as this can be more efficient for certain probes.
56+
if unique_id is not None:
57+
for cls in klasses:
58+
probe = cls.get_probe_with_id(unique_id, is_explicit)
59+
if probe is not None:
60+
return [probe]
61+
62+
# No full match, so ask probe classes for probes.
5463
for cls in klasses:
5564
probes += cls.get_all_connected_probes(unique_id, is_explicit)
5665

pyocd/probe/debug_probe.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,14 @@ class Capability(Enum):
6363
def get_all_connected_probes(cls, unique_id=None, is_explicit=False):
6464
"""! @brief Returns a list of DebugProbe instances.
6565
66+
To filter the list of returned probes, the `unique_id` parameter may be set to a string with a full or
67+
partial unique ID (canonically the serial number). Alternatively, the probe class may simply return all
68+
available probes and let the caller handle filtering.
69+
6670
@param cls The class instance.
67-
@param unique_id Optional unique ID value on which probes are being filtered. May be
68-
used by the probe to optimize retreiving the probe list.
69-
@param is_explicit Whether the probe type was explicitly specified in the unique ID. This
71+
@param unique_id String. Optional partial unique ID value used to filter available probes. May be used by the
72+
probe to optimize retreiving the probe list; there is no requirement to filter the results.
73+
@param is_explicit Boolean. Whether the probe type was explicitly specified in the unique ID. This
7074
can be used, for instance, to specially interpret the unique ID as an IP address or
7175
domain name when the probe class was specifically requested but not for general lists
7276
of available probes.
@@ -78,12 +82,11 @@ def get_all_connected_probes(cls, unique_id=None, is_explicit=False):
7882
def get_probe_with_id(cls, unique_id, is_explicit=False):
7983
"""! @brief Returns a DebugProbe instance for a probe with the given unique ID.
8084
81-
If no probe is connected with a matching unique ID, then None will be returned.
85+
If no probe is connected with a fully matching unique ID, then None will be returned.
8286
8387
@param cls The class instance.
84-
@param unique_id Optional unique ID value on which probes are being filtered. May be
85-
used by the probe to optimize retreiving the probe list.
86-
@param is_explicit Whether the probe type was explicitly specified in the unique ID.
88+
@param unique_id Unique ID string to match against probes' full unique ID. No partial matches are allowed.
89+
@param is_explicit Boolean. Whether the probe type was explicitly specified in the unique ID.
8790
@return DebugProbe instance, or None
8891
"""
8992
raise NotImplementedError()

pyocd/probe/jlink_probe.py

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,18 @@ def _get_jlink(cls):
5454
)
5555
except TypeError:
5656
return None
57+
58+
@classmethod
59+
def _format_serial_number(cls, serial_number):
60+
return "{:d}".format(serial_number)
5761

5862
@classmethod
5963
def get_all_connected_probes(cls, unique_id=None, is_explicit=False):
6064
try:
6165
jlink = cls._get_jlink()
6266
if jlink is None:
6367
return []
64-
return [cls(str(info.SerialNumber)) for info in jlink.connected_emulators()]
68+
return [cls(cls._format_serial_number(info.SerialNumber)) for info in jlink.connected_emulators()]
6569
except JLinkException as exc:
6670
six.raise_from(cls._convert_exception(exc), exc)
6771

@@ -72,43 +76,60 @@ def get_probe_with_id(cls, unique_id, is_explicit=False):
7276
if jlink is None:
7377
return None
7478
for info in jlink.connected_emulators():
75-
if str(info.SerialNumber) == unique_id:
76-
return cls(str(info.SerialNumber))
79+
sn = cls._format_serial_number(info.SerialNumber)
80+
if sn == unique_id:
81+
return cls(sn)
82+
else:
83+
return None
84+
except JLinkException as exc:
85+
six.raise_from(cls._convert_exception(exc), exc)
86+
87+
@classmethod
88+
def _get_probe_info(cls, serial_number, jlink):
89+
"""! @brief Look up and return a JLinkConnectInfo for the probe with matching serial number.
90+
@param cls The class object.
91+
@param serial_number String serial number. Must be the full serial number.
92+
@return JLinkConnectInfo object or None if there was no match.
93+
"""
94+
try:
95+
for info in jlink.connected_emulators():
96+
if cls._format_serial_number(info.SerialNumber) == serial_number:
97+
return info
7798
else:
7899
return None
79100
except JLinkException as exc:
80101
six.raise_from(cls._convert_exception(exc), exc)
81102

82103
def __init__(self, serial_number):
104+
"""! @brief Constructor.
105+
@param self The object.
106+
@param serial_number String. The J-Link's serial number.
107+
"""
83108
super(JLinkProbe, self).__init__()
84109
self._link = self._get_jlink()
85110
if self._link is None:
86111
raise exceptions.ProbeError("unable to open JLink DLL")
87112

113+
info = self._get_probe_info(serial_number, self._link)
114+
if info is None:
115+
raise exceptions.ProbeError("could not find JLink probe with serial number '{}'".format(serial_number))
116+
88117
self._serial_number = serial_number
118+
self._serial_number_int = int(serial_number, base=10)
89119
self._supported_protocols = None
90120
self._protocol = None
91121
self._default_protocol = None
92122
self._is_open = False
93123
self._dp_select = -1
94-
self._product_name = None
95-
self._oem = None
96-
97-
# Get some strings by temporarily opening.
98-
try:
99-
self.open()
100-
self._product_name = self._link.product_name
101-
self._oem = self._link.oem
102-
finally:
103-
self.close()
124+
self._product_name = six.ensure_str(info.acProduct)
104125

105126
@property
106127
def description(self):
107128
return self.vendor_name + " " + self.product_name
108129

109130
@property
110131
def vendor_name(self):
111-
return self._oem or "Segger"
132+
return "Segger"
112133

113134
@property
114135
def product_name(self):
@@ -137,7 +158,7 @@ def capabilities(self):
137158

138159
def open(self):
139160
try:
140-
self._link.open(self._serial_number)
161+
self._link.open(self._serial_number_int)
141162
self._is_open = True
142163

143164
# Get available wire protocols.
@@ -147,7 +168,9 @@ def open(self):
147168
self._supported_protocols.append(DebugProbe.Protocol.JTAG)
148169
if ifaces & (1 << pylink.enums.JLinkInterfaces.SWD):
149170
self._supported_protocols.append(DebugProbe.Protocol.SWD)
150-
assert len(self._supported_protocols) > 1
171+
if not len(self._supported_protocols) >= 2: # default + 1
172+
raise exceptions.ProbeError("J-Link probe {} does not support any known wire protocols".format(
173+
self.unique_id))
151174

152175
# Select default protocol, preferring SWD over JTAG.
153176
if DebugProbe.Protocol.SWD in self._supported_protocols:

0 commit comments

Comments
 (0)