11# Copyright (c) 2017 Linaro Limited.
2+ # Copyright (c) 2024 Tenstorrent AI ULC
23#
34# SPDX-License-Identifier: Apache-2.0
45#
78'''Runner for openocd.'''
89
910import re
10- import socket
1111import subprocess
12- import time
1312
1413from os import path
1514from 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