Import
Methods
The Net-based API provides methods for embedded debugging operations.Method Reference
Net.get(name, type=NetType.Debug)
Get a debug net by name.
Returns: Debug Net instance
Note: The debug net must be configured with the target device name stored in the
channel field (e.g., ‘NRF52840_XXAA’, ‘R7FA0E107’).
connect(speed=None, transport=None, *, force=False, ignore_if_connected=False, script=None, openocd_config=None, jlink_script=None, halt=False)
Connect to the target device (start the gdbserver for this probe). The backend
(J-Link or OpenOCD) is chosen automatically from the probe.
Returns:
dict - Status dictionary with connection information
A script override takes effect only when the gdbserver relaunches. If a server is
already up, pass
force=True to restart it with the new script.
ignore_if_connected=True returns early and does not relaunch, but it still
repoints the file for later operations. Invalid input means a missing path that
is not valid base64, or an empty string. The net ignores such input silently, and
the script that it materialized earlier stays in effect.The override is scoped to this net and this session. Lager writes it to a
per-net path rather than to the box-wide config that the net record and the HTTP
debug service share. disconnect() clears the override. Two debug nets that
connect with different scripts therefore no longer clobber one another.disconnect()
Disconnect from the target device.
dict - Status dictionary
reset(halt=False)
Reset the device.
Returns:
str - Combined output from reset operation
Self-heal (both backends): Right after a flash() there is a short window
where the debug server is not reachable yet. On J-Link the cause is that the
restarted GDB server’s PID is not observable yet. On OpenOCD the cause is a
transient daemon or RPC fault. A bare call raises inside that window. reset()
retries with bounded backoff on both the J-Link and OpenOCD backends, and it
restarts a server only when one is genuinely down. It never tears down a server
that is already up, so an attached RTT session stays intact. Callers no longer
need their own retry wrappers.
DA1469x exception: On DA1469x, flash() deliberately leaves the server down.
The flash ends in a software reset rather than a server restart, and the
documented flow is an explicit, halt-aware reconnect. So the self-heal still
retries on DA1469x, but it never auto-starts a server. A server that is genuinely
down still surfaces the original error, exactly as before. The self-heal never
brings a server up unhalted, because an unhalted server can return garbage
QSPI-XIP reads.
halt()
Halt the target where it is, without a reset. OpenOCD only.
str - Combined output from the halt operation
This is not the same as reset(halt=True). That runs OpenOCD’s reset halt,
which pulses nRESET and re-enters through the reset vector. halt() issues a bare
halt instead, so the core stops where it is, and nRESET is never touched.
The distinction matters on parts that execute in place out of QSPI. After you
program such a part, reset(halt=True) re-runs the bootloader rather than
stopping on the image you just wrote. An unhalted re-attach risks garbage XIP
reads. Halting in place is how you attach after a program without disturbing
the image.
J-Link has no standalone halt-in-place primitive, because
reset_device and
gdb_reset both reset first. On that backend halt() raises, and the error
names the halt-first .JLinkScript as the supported route.flash(firmware_path, flash_address=None)
Flash firmware to the device.
Returns:
str - Combined output from flash operation
Note: A .bin has no embedded address, so flash() raises without
flash_address rather than defaulting to 0x0. Pass the target’s flash base:
STM32 0x08000000, nRF52 0x00000000, DA1469x QSPI 0x16000000.
DA1469x on OpenOCD: mainline OpenOCD has no flash driver for the DA1469x’s
external QSPI. On that family, flash() and erase() drive the RAM-resident
flash_loader instead, the same path lager debug <net> flash takes. Pass the
absolute XIP address (0x16000000), exactly as on J-Link. The loader artefacts
live on the box under
/home/www-data/customer-binaries/openocd/flash-loaders/da1469x/. A missing
loader raises rather than falling back to OpenOCD’s program, which cannot
reach QSPI.
erase()
Perform full chip erase. This erases ALL flash memory including protection settings.
On a DA1469x behind an OpenOCD probe this is the flash_loader’s range erase of
the first 1 MiB of QSPI, matching the J-Link path.
str - Combined output from erase operation
read_memory(address, length)
Read memory from the target device.
Returns:
bytes - Memory data
Self-heal: like reset(), read_memory() retries with bounded backoff across
the brief post-flash() settling window on both backends. It reconnects only when
no server is up, and it never disturbs a live session. erase() behaves the same
way. The same DA1469x exception applies. No server is auto-started, so a
post-flash DA1469x read raises clearly rather than returning unhalted-XIP garbage.
status()
Get the current connection status.
dict - running (bool), pid and backend.
This reports whether a gdbserver process is up for the probe. It is not a
statement about the target: a server can outlive the part it was attached to.
The CLI’s lager debug <net> status reports both states separately.
session(speed=None, transport=None, connect=True, ignore_if_connected=True, disconnect_on_exit=True)
Scoped debug session. It connects on entry and guarantees teardown on exit. The
safe flash → attach-RTT → reset ordering is therefore encoded once, rather than
rediscovered in every script. The with target is the net itself, so the full
surface (flash, rtt_defmt, reset, read_memory, …) is available inside the
block.
Returns: a context manager yielding the debug net.
Why it pairs with RTT: the in-process RTT reader is reconnect-aware (see
below). A
flash() or reset() inside the session can bounce the GDB server.
Such a bounce does not kill a log stream that you opened in the same block.
rtt(channel=0, search_addr=None, search_size=None, chunk_size=None)
Create an RTT (Real-Time Transfer) session for bidirectional communication with the target device.
Returns: RTT context manager with methods:
read_some(timeout)- Read available data with timeout (returns bytes or None)write(data)- Write data to target (accepts bytes or str)
connect() first.
Reconnect-aware (both backends): the RTT reader re-attaches by itself when the
GDB server or daemon restarts under it.
-
J-Link. A
flash()briefly frees the probe’s USB and restarts the GDB server on the same ports, which drops the RTT socket. Areset()does the same through its Commander grab. The reader re-attaches to the same RTT telnet port instead of going silent. A long-livedread_some()orrtt_defmt()loop therefore keeps producing across a flash. -
OpenOCD. The daemon stays up across an ordinary flash, so the socket rarely
drops. If it does drop, from a daemon force-restart or an rtt-server bounce, the
reader re-runs
rtt setupandrtt server startand re-attaches.
reconnect=False for the legacy one-shot behavior.
Examples
Flash Firmware and Reset
Chip Erase Before Programming
Read Memory
CLI Commands (Recommended)
For most use cases, the CLI provides a simpler interface:RTT Streaming
SEGGER Real-Time Transfer (RTT) enables high-speed bidirectional communication with embedded devices during debugging (faster than UART, no timing impact).Decoding defmt logs with rtt_defmt()
rtt_defmt(elf, channel=0) opens an RTT session and pipes it through defmt-print (preinstalled on the Lager Box), yielding decoded log lines instead of raw bytes. The elf must be the exact firmware flashed on the target — defmt needs its symbol metadata to decode.
rtt_defmt() returns a context manager exposing:
Like the CLI pipe, the RTT stream never ends on its own. Bound your read loop with
a time budget or a line count, then exit the
with block.
Driving the firmware while decoding its logs
write() makes a decoding session bi-directional, so a script can send a command
and assert on the decoded response. Decoding is one-way — defmt-print only sees
the up-channel — so writes bypass it and go straight to the target. This is the
only way to do both at once. The RTT telnet port accepts a single client, so you
cannot open a raw rtt() alongside a rtt_defmt().
CLI Alternative: For interactive tailing, pipe the CLI directly:
lager debug <net> gdbserver --box <box> --rtt 2>/dev/null | defmt-print -e build/app.elf. See the CLI Debug Reference. Use rtt_defmt() when you need to assert on log content inside a test script; use the pipe when you just want to watch logs.
Supported Devices
J-Link supports a wide range of ARM Cortex-M and other microcontrollers. Common device names:
For a complete list, see SEGGER’s supported devices.
Supported Hardware
Notes
- Debug nets must be configured with the target device name in the
channelfield - The CLI (
lager debug) is recommended for most use cases - Python Net API is intended for advanced automation scripts running on the Lager Box
- Always call
disconnect()when finished to release the debug probe - Use
erase()to perform a full chip erase and clear protection settings - RTT requires an active debug connection (see RTT Streaming section above)

