-
Notifications
You must be signed in to change notification settings - Fork 199
Resource: add Segger J-Link support #1175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #1175 +/- ##
========================================
+ Coverage 63.0% 63.4% +0.4%
========================================
Files 160 161 +1
Lines 11865 11959 +94
========================================
+ Hits 7480 7588 +108
+ Misses 4385 4371 -14 ☔ View full report in Codecov by Sentry. |
I added testing of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For new resources, there should also be a corresponding driver. As there is already a Python module which provides access, only a very simple driver is needed to load it and wrap the open method. Take a look at these:
8ed0405
to
753a3b3
Compare
@jluebbe driver added with 100% code coverage. |
@jluebbe does my driver meet your expectations? |
labgrid/remote/exporter.py
Outdated
child = self.child | ||
self.child = None | ||
port = self.port | ||
self.port = None | ||
child.terminate() | ||
try: | ||
child.wait(2.0) # JLinkRemoteServer takes about a second to react | ||
except subprocess.TimeoutExpired: | ||
self.logger.warning("JLinkRemoteServer for %s still running after SIGTERM", self.local.serial) | ||
log_subprocess_kernel_stack(self.logger, child) | ||
child.kill() | ||
child.wait(1.0) | ||
self.logger.info("stopped JLinkRemoteServer for %s on port %d", self.local.serial, port) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When operating with pipes (stdout=subprocess.PIPE
), they should be closed explicitly when the
subprocess has terminated (see also #1018).
""" | ||
|
||
def __attrs_post_init__(self): | ||
self.match["ID_VENDOR_ID"] = "1366" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since USBDebugger now covers the same vendor & model ID as JLinkDevice, do I need to refactor to use USBDebugger instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, please do so.
Add a driver and resource for the Segger J-Link debug probe. Export the J-Link resource over IP using the J-Link Remote Server. Signed-off-by: Paul Vittorino <[email protected]>
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems unrelated.
- `JLinkDriver`_ | ||
|
||
NetworkJLinkDevice | ||
~~~~~~~~~~~~~~~~~~~~~ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
~~~~~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~~ |
# Workaround for Debian's /etc/hosts entry | ||
# https://www.debian.org/doc/manuals/debian-reference/ch05.en.html#_the_hostname_resolution | ||
if ip_addr == "127.0.1.1": | ||
ip_addr = "127.0.0.1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't we use 127.0.1.1 here?
""" | ||
|
||
def __attrs_post_init__(self): | ||
self.match["ID_VENDOR_ID"] = "1366" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, please do so.
class USBJLinkExport(USBGenericExport): | ||
"""Export J-Link device using the J-Link Remote Server""" | ||
|
||
def __attrs_post_init__(self): | ||
super().__attrs_post_init__() | ||
self.child = None | ||
self.port = None | ||
self.tool = '/opt/SEGGER/JLink/JLinkRemoteServer' | ||
|
||
def _get_params(self): | ||
"""Helper function to return parameters""" | ||
return { | ||
'host': self.host, | ||
'port': self.port, | ||
'busnum': self.local.busnum, | ||
'devnum': self.local.devnum, | ||
'path': self.local.path, | ||
'vendor_id': self.local.vendor_id, | ||
'model_id': self.local.model_id, | ||
} | ||
|
||
def __del__(self): | ||
if self.child is not None: | ||
self.stop() | ||
|
||
def _start(self, start_params): | ||
"""Start ``JLinkRemoteServer`` subprocess""" | ||
assert self.local.avail | ||
assert self.child is None | ||
self.port = get_free_port() | ||
|
||
cmd = [ | ||
self.tool, | ||
"-Port", | ||
f"{self.port}", | ||
"-select", | ||
f"USB={self.local.serial}", | ||
] | ||
self.logger.info("Starting JLinkRemoteServer with: %s", " ".join(cmd)) | ||
self.child = subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True) | ||
|
||
# Wait for the server to be ready for incoming connections | ||
# Waiting to open the socket with Python does not work | ||
timeout = Timeout(10.0) | ||
while not timeout.expired: | ||
line = self.child.stdout.readline().rstrip() | ||
self.logger.debug(line) | ||
if "Waiting for client connections..." in line: | ||
break | ||
|
||
if timeout.expired: | ||
raise TIMEOUT( | ||
f"Timeout of {timeout.timeout} seconds exceeded during waiting for J-Link Remote Server startup" | ||
) | ||
self.logger.info("started JLinkRemoteServer for %s on port %d", self.local.serial, self.port) | ||
|
||
def _stop(self, start_params): | ||
"""Stop ``JLinkRemoteServer`` subprocess""" | ||
assert self.child | ||
child = self.child | ||
self.child = None | ||
port = self.port | ||
self.port = None | ||
child.terminate() | ||
try: | ||
child.communicate(2.0) # JLinkRemoteServer takes about a second to react | ||
except subprocess.TimeoutExpired: | ||
self.logger.warning("JLinkRemoteServer for %s still running after SIGTERM", self.local.serial) | ||
log_subprocess_kernel_stack(self.logger, child) | ||
child.kill() | ||
child.communicate(1.0) | ||
self.logger.info("stopped JLinkRemoteServer for %s on port %d", self.local.serial, port) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not be required. The driver should start the remote server on activate and stop it on deactivate.
|
||
def update(self): | ||
super().update() | ||
self.serial = self.device.properties.get('ID_SERIAL_SHORT') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.device
might be None
here. Maybe make it a @property
?
@target_factory.reg_driver | ||
@attr.s(eq=False) | ||
class JLinkDriver(Driver): | ||
bindings = {"jlink_device": {"JLinkDevice", "NetworkJLinkDevice"}, } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe s/jlink_device/device/
? Since we know that we are in the jlink context anyways.
@@ -1789,6 +1809,21 @@ Arguments: | |||
- board_config (str): optional, board config in the ``openocd/scripts/board/`` directory | |||
- load_commands (list of str): optional, load commands to use instead of ``init``, ``bootstrap {filename}``, ``shutdown`` | |||
|
|||
JLinkDriver | |||
~~~~~~~~~~~~~ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
~~~~~~~~~~~~~ | |
~~~~~~~~~~~ |
Description
Add a resource for the Segger J-Link debug probe.
Export the J-Link resource over IP using the J-Link Remote Server.
Adding support for J-Link over IP combined with pylink provides a Python interface for the J-Link over IP.
Verified by acquiring a place via the Python API and using pylink to establish an IP connection.
Supported hardware includes Segger J-Link JTAG probes. Tested with J-Link Ultra+ Version 5.0 hardware.
Checklist