Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion cmake/flash/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ endif()

# Generate the flash, debug, debugserver, attach targets within the build
# system itself.
foreach(target flash debug debugserver attach)
foreach(target flash debug debugserver attach rtt)
if(target STREQUAL flash)
set(comment "Flashing ${BOARD}")
elseif(target STREQUAL debug)
Expand All @@ -168,6 +168,8 @@ foreach(target flash debug debugserver attach)
endif()
elseif(target STREQUAL attach)
set(comment "Debugging ${BOARD}")
elseif(target STREQUAL rtt)
set(comment "RTT ${BOARD}")
endif()
string(TOUPPER ${target} TARGET_UPPER)

Expand Down
2 changes: 1 addition & 1 deletion scripts/west_commands/debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def __init__(self):
'open an rtt shell',
"",
accepts_unknown_args=True)
self.runner_key = 'rtt-runner' # in runners.yaml
self.runner_key = 'debug-runner' # in runners.yaml

def do_add_parser(self, parser_adder):
return add_parser_common(self, parser_adder)
Expand Down
4 changes: 4 additions & 0 deletions scripts/west_commands/runners/jlink.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ def print_gdbserver_message(self):
self.logger.info('J-Link GDB server running on port '
f'{self.gdb_port}{thread_msg}')

def print_rttserver_message(self):
self.logger.info(f'J-Link RTT server running on port {self.rtt_port}')

@property
def jlink_version(self):
# Get the J-Link version as a (major, minor, rev) tuple of integers.
Expand Down Expand Up @@ -276,6 +279,7 @@ def do_run(self, command, **kwargs):
self.check_call(server_cmd)
elif command == 'rtt':
self.print_gdbserver_message()
self.print_rttserver_message()
server_cmd += ['-nohalt']
server_proc = self.popen_ignore_int(server_cmd)
try:
Expand Down
128 changes: 49 additions & 79 deletions scripts/west_commands/runners/openocd.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Copyright (c) 2017 Linaro Limited.
# Copyright (c) 2024 Tenstorrent AI ULC
#
# SPDX-License-Identifier: Apache-2.0
#
Expand All @@ -7,9 +8,7 @@
'''Runner for openocd.'''

import re
import socket
import subprocess
import time

from os import path
from pathlib import Path
Expand All @@ -29,6 +28,18 @@
DEFAULT_OPENOCD_RESET_HALT_CMD = 'reset init'
DEFAULT_OPENOCD_TARGET_HANDLE = "_TARGETNAME"

def to_num(number):
dev_match = re.search(r"^\d*\+dev", number)
dev_version = dev_match is not None

num_match = re.search(r"^\d*", number)
num = int(num_match.group(0))

if dev_version:
num += 1

return num

class OpenOcdBinaryRunner(ZephyrBinaryRunner):
'''Runner front-end for openocd.'''

Expand Down Expand Up @@ -200,18 +211,8 @@ def print_gdbserver_message(self):
self.logger.info('OpenOCD GDB server running on port '
f'{self.gdb_port}{thread_msg}')

# pylint: disable=R0201
def to_num(self, number):
dev_match = re.search(r"^\d*\+dev", number)
dev_version = not dev_match is None

num_match = re.search(r"^\d*", number)
num = int(num_match.group(0))

if dev_version:
num += 1

return num
def print_rttserver_message(self):
self.logger.info(f'OpenOCD RTT server running on port {self.rtt_port}')

def read_version(self):
self.require(self.openocd_cmd[0])
Expand All @@ -223,7 +224,7 @@ def read_version(self):
version_match = re.search(r"Open On-Chip Debugger (\d+.\d+.\d+)", out)
version = version_match.group(1).split('.')

return [self.to_num(i) for i in version]
return [to_num(i) for i in version]

def supports_thread_info(self):
# Zephyr rtos was introduced after 0.11.0
Expand All @@ -246,12 +247,10 @@ def do_run(self, command, **kwargs):
self.do_flash_elf(**kwargs)
elif command == 'flash':
self.do_flash(**kwargs)
elif command in ('attach', 'debug'):
self.do_attach_debug(command, **kwargs)
elif command in ('attach', 'debug', 'rtt'):
self.do_attach_debug_rtt(command, **kwargs)
elif command == 'load':
self.do_load(**kwargs)
elif command == 'rtt':
self.do_rtt(**kwargs)
else:
self.do_debugserver(**kwargs)

Expand Down Expand Up @@ -344,7 +343,7 @@ def do_flash_elf(self, **kwargs):

self.check_call(cmd)

def do_attach_debug(self, command, **kwargs):
def do_attach_debug_rtt(self, command, **kwargs):
if self.gdb_cmd is None:
raise ValueError('Cannot debug; no gdb specified')
if self.elf_name is None:
Expand Down Expand Up @@ -375,10 +374,39 @@ def do_attach_debug(self, command, **kwargs):
for i in self.gdb_init:
gdb_cmd.append("-ex")
gdb_cmd.append(i)
if command == 'rtt':
rtt_address = self.get_rtt_address()
if rtt_address is None:
raise ValueError("RTT Control block not be found")

# cannot prompt the user to press return for automation purposes
gdb_cmd.extend(['-ex', 'set pagination off'])
# start the internal openocd rtt service via gdb monitor commands
gdb_cmd.extend(
['-ex', f'monitor rtt setup 0x{rtt_address:x} 0x10 "SEGGER RTT"'])
gdb_cmd.extend(['-ex', 'monitor reset run'])
gdb_cmd.extend(['-ex', 'monitor rtt start'])
gdb_cmd.extend(
['-ex', f'monitor rtt server start {self.rtt_port} 0'])
# detach from the target and quit the gdb client session
gdb_cmd.extend(['-ex', 'detach', '-ex', 'quit'])

self.require(gdb_cmd[0])
self.print_gdbserver_message()
self.run_server_and_client(server_cmd, gdb_cmd)

if command in ('attach', 'debug'):
self.run_server_and_client(server_cmd, gdb_cmd)
elif command == 'rtt':
self.print_rttserver_message()
server_proc = self.popen_ignore_int(server_cmd)
try:
# run the binary with gdb, set up the rtt server (runs to completion)
subprocess.run(gdb_cmd)
# run the rtt client in the foreground
self.run_telnet_client('localhost', self.rtt_port)
finally:
server_proc.terminate()
server_proc.wait()

def do_debugserver(self, **kwargs):
pre_init_cmd = []
Expand All @@ -399,61 +427,3 @@ def do_debugserver(self, **kwargs):
['-c', self.reset_halt_cmd])
self.print_gdbserver_message()
self.check_call(cmd)

def do_rtt(self, **kwargs):
pre_init_cmd = []
for i in self.pre_init:
pre_init_cmd.append("-c")
pre_init_cmd.append(i)

if self.thread_info_enabled and self.supports_thread_info():
pre_init_cmd.append("-c")
rtos_command = f'${self.target_handle} configure -rtos Zephyr'
pre_init_cmd.append(rtos_command)

rtt_address = self.get_rtt_address()
if rtt_address is None:
raise ValueError("RTT Control block not be found")

rtt_cmds = [
'-c', f'rtt setup 0x{rtt_address:x} 0x10 "SEGGER RTT"',
'-c', f'rtt server start {self.rtt_port} 0',
'-c', 'rtt start',
]

server_cmd = (self.openocd_cmd + self.cfg_cmd +
['-c', f'tcl_port {self.tcl_port}',
'-c', f'telnet_port {self.telnet_port}',
'-c', f'gdb_port {self.gdb_port}'] +
pre_init_cmd + self.init_arg + self.targets_arg +
['-c', self.reset_halt_cmd] +
rtt_cmds
)
self.print_gdbserver_message()
server_proc = self.popen_ignore_int(server_cmd)
# The target gets halted after all commands passed on the commandline are run.
# The only way to run resume here, to not have to connect a GDB, is to connect
# to the tcl port and run the command. When the TCL port comes up, initialization
# is done.
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# As long as the server process is still running, keep retrying the connection
while server_proc.poll() is None:
try:
sock.connect(('localhost', self.tcl_port))
break
except ConnectionRefusedError:
time.sleep(0.1)
# \x1a is the command terminator for the openocd tcl rpc
sock.send(b'resume\x1a')
sock.shutdown(socket.SHUT_RDWR)
# Run the client. Since rtt is initialized before the tcl rpc comes up,
# the port is open now.
self.logger.info("Opening RTT")
time.sleep(0.1) # Give the server a moment to output log messages first
self.run_telnet_client('localhost', self.rtt_port)
except Exception as e:
self.logger.error(e)
finally:
server_proc.terminate()
server_proc.wait()
Loading