Python implementation of an RTT to PTY bridge using pylink. This is functionally equivalent to rtt2pty, but uses pylink instead of directly calling libjlinkarm.so via dlopen.
Repository: https://github.com/fxd0h/rtt2py_pylink
The script connects to a J-Link debugger, configures RTT (Real-Time Transfer), finds the specified RTT buffers, and creates a pseudo-terminal (PTY) that bridges the RTT communication. Data from the target device flows through RTT buffers and appears on the PTY, making it accessible as a standard terminal device.
- Python 3.7 or higher
- pylink library from https://github.com/fxd0h/pylink-nrf54-rttFix
- SEGGER J-Link Software with libjlinkarm.so installed
This project uses a modified version of pylink (https://github.com/fxd0h/pylink-nrf54-rttFix) rather than the original Square/pylink repository. The modified version includes important improvements to RTT Control Block (CB) detection that are essential for reliable operation across various devices.
The key improvements include:
- Enhanced RTT Control Block detection: Improved search algorithm and multiple stop/start cycles to ensure clean RTT state before detection
- Better search range handling: Proper implementation of
SetRTTSearchRangescommand according to SEGGER documentation (UM08001) - Increased wait times: Additional delays after setting search ranges and after START command to allow RTT to properly initialize
- Device state verification: Ensures the target device is running before attempting RTT start, as RTT requires an active CPU
These changes address issues where RTT auto-detection could fail on some devices, especially when the control block location is not known in advance. The original pylink implementation had limitations that could cause RTT detection to fail silently or timeout incorrectly.
Basic usage - connect to device and bridge default Terminal buffer:
python3 rtt2pty_pylink.py -d NRF54L15_M33 -b TerminalList available RTT buffers:
python3 rtt2pty_pylink.py -d NRF54L15_M33 -pSpecify RTT control block address directly:
python3 rtt2pty_pylink.py -d NRF54L15_M33 -a 0x200044E0Use search range for RTT auto-detection:
python3 rtt2pty_pylink.py -d NRF54L15_M33 -a 0x20000000,0x2003FFFFEnable bidirectional communication (read from PTY and write to RTT):
python3 rtt2pty_pylink.py -d NRF54L15_M33 -b Terminal --bidirCreate a symlink to the PTY for easier access:
python3 rtt2pty_pylink.py -d NRF54L15_M33 -b Terminal -l /tmp/rttSelect specific J-Link by serial number:
python3 rtt2pty_pylink.py -d NRF54L15_M33 -s 12345678-d, --device: Target device name (default: NRF54L15_M33)-s, --serial: J-Link serial number-S, --speed: SWD/JTAG speed in kHz (default: 4000)-b, --buffer: RTT buffer name to use (default: Terminal)-2, --bidir: Enable bidirectional communication-a, --address: RTT control block address (hex) or search range (start,size)-l, --link: Create symlink to PTY at specified path-p, --print-bufs: Print list of available buffers and exit
The implementation uses pylink's RTT API which provides all the necessary functionality:
- Connection: Opens J-Link connection using
jlink.open()andjlink.connect() - RTT Configuration: Configures RTT search ranges or specific address using
jlink.rtt_start() - Buffer Discovery: Finds buffers by name using
rtt_get_buf_descriptor()in a loop - PTY Creation: Creates pseudo-terminal using Python's
pty.openpty()module - Data Transfer: Reads from RTT buffers with
rtt_read()and writes to PTY, optionally reading from PTY and writing back withrtt_write()
All RTT operations available in rtt2pty are available in pylink:
rtt_start()- Start RTT with optional search ranges or specific addressrtt_get_num_up_buffers()/rtt_get_num_down_buffers()- Get buffer countsrtt_get_buf_descriptor()- Get buffer information by indexrtt_read()- Read data from RTT bufferrtt_write()- Write data to RTT bufferrtt_stop()- Stop RTT session
The main difference from rtt2pty is that pylink provides a higher-level Python API instead of direct C function calls. This makes the code simpler and easier to maintain while providing the same functionality.
The original rtt2pty uses dlopen to load libjlinkarm.so and calls C functions directly:
jlink_emu_selectbyusbsn(opt_sn);
jlink_open();
jlink_execcommand("device=NRF54L15_M33", NULL, 0);
jlink_tif_select(1);
jlink_setspeed(4000);
jlink_connect();
jlink_rtterminal_control(RTT_CONTROL_START, NULL);With pylink, the equivalent is:
jlink = pylink.JLink()
jlink.open(serial_no=opt_sn)
jlink.set_tif(pylink.enums.JLinkInterfaces.SWD)
jlink.set_speed(4000)
jlink.connect('NRF54L15_M33')
jlink.rtt_start()The pylink version is cleaner and handles errors through exceptions rather than return codes. PTY creation is also simpler using Python's standard library:
master_fd, slave_fd = pty.openpty()
pty_name = os.ttyname(slave_fd)Instead of the C version requiring multiple system calls:
int fdm = posix_openpt(O_RDWR);
grantpt(fdm);
unlockpt(fdm);
printf("PTY name is %s\n", ptsname(fdm));The script implements a main loop that:
- Reads data from the RTT UP buffer (target to host)
- Writes that data to the PTY master file descriptor
- If bidirectional mode is enabled, reads from PTY and writes to RTT DOWN buffer (host to target)
The loop uses select() for non-blocking PTY reads when bidirectional mode is active, and sleeps briefly when no data is available to avoid busy-waiting.
Signal handlers are set up for SIGINT, SIGTERM, and SIGQUIT to allow clean shutdown. On exit, the script stops RTT, closes file descriptors, and removes any symlinks that were created.
The script searches through available buffers to find one matching the specified name:
def find_buffer_by_name(jlink, name, up=True):
num_buffers = (jlink.rtt_get_num_up_buffers() if up
else jlink.rtt_get_num_down_buffers())
for index in range(num_buffers):
desc = jlink.rtt_get_buf_descriptor(index, up)
if desc.name.decode('utf-8').rstrip('\x00') == name:
return index, desc
return -1, NoneThis matches the functionality of rtt2pty's buffer search, which iterates through buffers and compares names using strcmp().
Mariano Abad (fxd0h)
Email: [email protected]
GitHub: @fxd0h
GitHub: https://github.com/fxd0h/rtt2py_pylink
- Original rtt2pty: https://github.com/codecoup/tools-rtt2pty
- pylink library: https://github.com/fxd0h/pylink-nrf54-rttFix - RTT API in
pylink/jlink.py(RTT functions around lines 5329-6092) - Python pty module: https://docs.python.org/3/library/pty.html