Skip to content

Commit b85e198

Browse files
cfriedtfabiobaltieri
authored andcommitted
west: runners: update the rtt implementation for openocd
Previously, rtt start would always fail because the target (i.e. firmware) had not been started. ``` Info : rtt: Searching for control block 'SEGGER RTT' Info : rtt: No control block found ``` When the command is 'rtt', run the binary via gdb before calling 'rtt start'. Firmware calls `SEGGER_RTT_Init()` shortly after init which allows OpenOCD to find the RTT control block. Similarly, only start the 'rtt server' after calling 'rtt start' to avoid any potential race conditions internally within OpenOCD. Signed-off-by: Chris Friedt <[email protected]>
1 parent 9a8ae21 commit b85e198

File tree

1 file changed

+37
-66
lines changed

1 file changed

+37
-66
lines changed

scripts/west_commands/runners/openocd.py

Lines changed: 37 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Copyright (c) 2017 Linaro Limited.
2+
# Copyright (c) 2024 Tenstorrent AI ULC
23
#
34
# SPDX-License-Identifier: Apache-2.0
45
#
@@ -7,9 +8,7 @@
78
'''Runner for openocd.'''
89

910
import re
10-
import socket
1111
import subprocess
12-
import time
1312

1413
from os import path
1514
from pathlib import Path
@@ -212,6 +211,9 @@ def print_gdbserver_message(self):
212211
self.logger.info('OpenOCD GDB server running on port '
213212
f'{self.gdb_port}{thread_msg}')
214213

214+
def print_rttserver_message(self):
215+
self.logger.info(f'OpenOCD RTT server running on port {self.rtt_port}')
216+
215217
def read_version(self):
216218
self.require(self.openocd_cmd[0])
217219

@@ -245,12 +247,10 @@ def do_run(self, command, **kwargs):
245247
self.do_flash_elf(**kwargs)
246248
elif command == 'flash':
247249
self.do_flash(**kwargs)
248-
elif command in ('attach', 'debug'):
249-
self.do_attach_debug(command, **kwargs)
250+
elif command in ('attach', 'debug', 'rtt'):
251+
self.do_attach_debug_rtt(command, **kwargs)
250252
elif command == 'load':
251253
self.do_load(**kwargs)
252-
elif command == 'rtt':
253-
self.do_rtt(**kwargs)
254254
else:
255255
self.do_debugserver(**kwargs)
256256

@@ -343,7 +343,7 @@ def do_flash_elf(self, **kwargs):
343343

344344
self.check_call(cmd)
345345

346-
def do_attach_debug(self, command, **kwargs):
346+
def do_attach_debug_rtt(self, command, **kwargs):
347347
if self.gdb_cmd is None:
348348
raise ValueError('Cannot debug; no gdb specified')
349349
if self.elf_name is None:
@@ -374,10 +374,39 @@ def do_attach_debug(self, command, **kwargs):
374374
for i in self.gdb_init:
375375
gdb_cmd.append("-ex")
376376
gdb_cmd.append(i)
377+
if command == 'rtt':
378+
rtt_address = self.get_rtt_address()
379+
if rtt_address is None:
380+
raise ValueError("RTT Control block not be found")
381+
382+
# cannot prompt the user to press return for automation purposes
383+
gdb_cmd.extend(['-ex', 'set pagination off'])
384+
# start the internal openocd rtt service via gdb monitor commands
385+
gdb_cmd.extend(
386+
['-ex', f'monitor rtt setup 0x{rtt_address:x} 0x10 "SEGGER RTT"'])
387+
gdb_cmd.extend(['-ex', 'monitor reset run'])
388+
gdb_cmd.extend(['-ex', 'monitor rtt start'])
389+
gdb_cmd.extend(
390+
['-ex', f'monitor rtt server start {self.rtt_port} 0'])
391+
# detach from the target and quit the gdb client session
392+
gdb_cmd.extend(['-ex', 'detach', '-ex', 'quit'])
377393

378394
self.require(gdb_cmd[0])
379395
self.print_gdbserver_message()
380-
self.run_server_and_client(server_cmd, gdb_cmd)
396+
397+
if command in ('attach', 'debug'):
398+
self.run_server_and_client(server_cmd, gdb_cmd)
399+
elif command == 'rtt':
400+
self.print_rttserver_message()
401+
server_proc = self.popen_ignore_int(server_cmd)
402+
try:
403+
# run the binary with gdb, set up the rtt server (runs to completion)
404+
subprocess.run(gdb_cmd)
405+
# run the rtt client in the foreground
406+
self.run_telnet_client('localhost', self.rtt_port)
407+
finally:
408+
server_proc.terminate()
409+
server_proc.wait()
381410

382411
def do_debugserver(self, **kwargs):
383412
pre_init_cmd = []
@@ -398,61 +427,3 @@ def do_debugserver(self, **kwargs):
398427
['-c', self.reset_halt_cmd])
399428
self.print_gdbserver_message()
400429
self.check_call(cmd)
401-
402-
def do_rtt(self, **kwargs):
403-
pre_init_cmd = []
404-
for i in self.pre_init:
405-
pre_init_cmd.append("-c")
406-
pre_init_cmd.append(i)
407-
408-
if self.thread_info_enabled and self.supports_thread_info():
409-
pre_init_cmd.append("-c")
410-
rtos_command = f'${self.target_handle} configure -rtos Zephyr'
411-
pre_init_cmd.append(rtos_command)
412-
413-
rtt_address = self.get_rtt_address()
414-
if rtt_address is None:
415-
raise ValueError("RTT Control block not be found")
416-
417-
rtt_cmds = [
418-
'-c', f'rtt setup 0x{rtt_address:x} 0x10 "SEGGER RTT"',
419-
'-c', f'rtt server start {self.rtt_port} 0',
420-
'-c', 'rtt start',
421-
]
422-
423-
server_cmd = (self.openocd_cmd + self.cfg_cmd +
424-
['-c', f'tcl_port {self.tcl_port}',
425-
'-c', f'telnet_port {self.telnet_port}',
426-
'-c', f'gdb_port {self.gdb_port}'] +
427-
pre_init_cmd + self.init_arg + self.targets_arg +
428-
['-c', self.reset_halt_cmd] +
429-
rtt_cmds
430-
)
431-
self.print_gdbserver_message()
432-
server_proc = self.popen_ignore_int(server_cmd)
433-
# The target gets halted after all commands passed on the commandline are run.
434-
# The only way to run resume here, to not have to connect a GDB, is to connect
435-
# to the tcl port and run the command. When the TCL port comes up, initialization
436-
# is done.
437-
try:
438-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
439-
# As long as the server process is still running, keep retrying the connection
440-
while server_proc.poll() is None:
441-
try:
442-
sock.connect(('localhost', self.tcl_port))
443-
break
444-
except ConnectionRefusedError:
445-
time.sleep(0.1)
446-
# \x1a is the command terminator for the openocd tcl rpc
447-
sock.send(b'resume\x1a')
448-
sock.shutdown(socket.SHUT_RDWR)
449-
# Run the client. Since rtt is initialized before the tcl rpc comes up,
450-
# the port is open now.
451-
self.logger.info("Opening RTT")
452-
time.sleep(0.1) # Give the server a moment to output log messages first
453-
self.run_telnet_client('localhost', self.rtt_port)
454-
except Exception as e:
455-
self.logger.error(e)
456-
finally:
457-
server_proc.terminate()
458-
server_proc.wait()

0 commit comments

Comments
 (0)