Skip to main content
lager diagnose <net> --box <box> [--type <role>] is a single-shot diagnosis for a misbehaving instrument net. It collapses the manual debug workflow (lsof, dmesg, bare pyvisa probes, hardware-service introspection) into one CLI call that returns an actionable classification — host-side, instrument-wedged, or healthy.
Introduced in lager 0.20.0 for USB-TMC (pyvisa) instruments. Extended in 0.28.3 to diagnose debug nets (SEGGER J-Link, and a basic OpenOCD/ST-Link path) — see Debug nets (J-Link) below.

Syntax

lager diagnose NET [OPTIONS]

Options

OptionDescription
--box BOXLagerbox name or IP address (uses the default box if omitted)
--type ROLENet role. Defaults to auto, which looks up the net’s role from the box’s saved nets. Pass an explicit role (battery, power-supply, scope, debug, usb, adc, …) to override, or to diagnose a net that isn’t saved. A debug net routes to the J-Link path.
NET is the name of the net to diagnose (e.g. battery1, supply1).

Usage

# Diagnose a net, auto-detecting its role from saved nets
lager diagnose battery1 --box my-lager-box

# Override the role explicitly
lager diagnose battery1 --box my-lager-box --type battery
The command queries three box-side endpoints in parallel and prints a section for each, followed by a one-line classification with the next step.

Output sections

USB (host-side)

From GET /diagnose/usb on box port 9000. Reports:
  • enumerated — does the device show up on the host’s USB bus?
  • sysfs — kernel sysfs path (e.g. /sys/bus/usb/devices/1-4).
  • device/dev/bus/usb/BBB/DDD path used by lsof/fuser.
  • usbtmc — whether the usbtmc kernel module is loaded (and therefore racing libusb for interface 0).
  • lsofcommand(pid) list of processes holding the USB device file.
  • dmesg tail — last few USB / usbtmc kernel messages.

VISA (instrument-side)

From GET /diagnose/visa on box port 9000. Opens a fresh pyvisa session and queries *IDN? with a short timeout. Skips the open (with a clear note) if the hardware service already holds a shared session for this address — collisions would either hang or return garbage. Reports:
  • idn — the IDN string if the instrument answered.
  • elapsed — wall-clock ms.
  • error / error_class — classified as busy, nodev, timeout, or other.
  • skipped — set when the hardware service holds the address.

Dispatcher (hw_service in-process)

From GET /diagnose/dispatcher on hardware-service port 8080. Reports the in-process state for this address:
  • cached_session — whether the shared pyvisa session pool has it.
  • cached_drivers — driver instances cached against this address.
  • shared_pool — total pool size.

Classifications

The decision tree, in order (first match wins):
ClassificationTrigger
HOST-SIDE: usbtmc kernel module loadedthe usbtmc kernel module is bound (run lager update to install the blacklist)
HOST-SIDE: USB device claimed by multiple processesVISA busy and two or more holders in lsof
HOST-SIDE: USB device busyVISA busy with a single holder
TRANSIENT: device disappeared from USBVISA nodev (re-enumeration)
INSTRUMENT WEDGEDVISA timeout — enumerates and opens, but won’t answer *IDN?
NOT ENUMERATEDthe device does not show up on USB (check power/cable)
HEALTHY*IDN? returned (IDN string shown)
HEALTHY (shared session)the open was skipped because hw_service holds an active session
TRANSIENT: enumerated as USB-TMC but fresh open failedUSB-TMC class but the fresh pyvisa open failed
NOT USB-TMCa vendor-SDK instrument (LabJack/LJM, Picoscope, Acroname, …), not pyvisa
UNCLEARfallback — review the per-section output

Sample session

$ lager diagnose battery1 --box my-lager-box
lager diagnose — my-lager-box → battery1
  NetType: battery    address: USB0::0x05E6::0x2281::4518305::INSTR

== USB (host-side) ==
   enumerated:   True
   usbtmc kmod:  not loaded (good)
   lsof:         no holders

== VISA (instrument-side) ==
   idn:          KEITHLEY INSTRUMENTS,MODEL 2281S-20-6,4518305,01.08b
   elapsed:      429 ms

== Dispatcher (hw_service in-process) ==
   cached_session:  False
   shared_pool:     0 entry/entries

Classification: HEALTHY — IDN: KEITHLEY INSTRUMENTS,MODEL 2281S-20-6,4518305,01.08b
A wedged instrument surfaces clearly so you stop trying software-only recoveries:
Classification: INSTRUMENT WEDGED: device enumerates and accepts session open,
but won't respond to *IDN?. The instrument firmware is stuck — a mains-side
power-cycle of the instrument itself is required.
Vendor-SDK instruments (LabJack, Picoscope, Acroname) don’t go through pyvisa, so lager diagnose points you at the role-specific command instead of returning a misleading UNCLEAR.
A debug net isn’t USB-TMC, so the pyvisa *IDN? probe above can’t reach it. When the net’s role is debug (auto-detected, or forced with --type debug), lager diagnose takes a J-Link-aware path instead: it fetches the same host-side USB section plus a dedicated /diagnose/jlink endpoint and walks the debug stack outside-in — software → USB → probe-visible → gdbserver → target connect — so the most specific actionable fault wins.
lager diagnose swd1 --box lab-lager-box            # auto-detects the debug role
lager diagnose swd1 --box lab-lager-box --type debug
In addition to the USB (host-side) section, a debug net prints a J-Link / debug probe section reporting:
  • backend — the probe backend (jlink, or an OpenOCD/ST-Link backend).
  • jlink software — whether the SEGGER J-Link tools are installed on the box.
  • probe enum — does the probe show up on the host’s USB bus?
  • probe visible — does JLinkExe actually enumerate the probe (with the emulator product/serial list)?
  • holderscommand(pid) of any process holding the probe (usually a stale gdbserver).
  • gdbserver — whether a J-Link gdbserver is running, its PID, and whether its logfile looks healthy.
  • connect — the result of a target-connect probe: connect_ok, an error class, VTref (target reference voltage), and the detected core. The raw JLinkExe output is shown when the failure can’t be classified.
A SEGGER probe gets the full stack above. A non-J-Link OpenOCD/ST-Link probe reports a lighter openocd-basic section (backend, probe enumeration, and gdbserver state) — deep target diagnosis is J-Link-only for now.

Debug classifications

ClassificationTrigger
HEALTHY: J-Link connected to <device>target connect succeeded (core, and VTref when J-Link reports it)
HEALTHY: J-Link gdbserver runninga gdbserver is up, listening, and its log is clean (active debug session)
J-LINK SOFTWARE MISSING on boxthe SEGGER J-Link tools aren’t installed (lager update installs them)
PROBE NOT ON USBthe probe isn’t enumerated — check cable, probe power, upstream hub port
PROBE CLAIMEDprobe is on USB but JLinkExe can’t see it because another process holds it (usually a stale gdbserver — lager debug <net> disconnect)
PROBE WEDGEDprobe is on USB but JLinkExe enumeration is empty — power-cycle the probe
GDBSERVER WEDGEDserver process is up but its log shows a target-connection failure
TARGET UNPOWEREDprobe is fine but VTref is too low — the target board has no power on the debug header (or VTref isn’t wired)
TARGET LOCKEDdebug access is blocked by readout/IDCODE/AP protection — a mass-erase/unlock is required (e.g. nrfjprog --recover)
DEVICE NAMEJLinkExe rejected the configured device — fix the net’s device/MCU field
NO TARGET COMMSprobe + target power OK but SWD/JTAG connect failed — check SWDIO/SWCLK wiring, nRST pull-up, SWD-vs-JTAG, try a lower speed
INCONCLUSIVE / UNCLEARconnect probe was skipped or returned an unrecognized class — review the section output and rerun

Sample debug session

$ lager diagnose swd1 --box lab-lager-box --type debug
lager diagnose — lab-lager-box → swd1
  NetType: debug    address: 50105878

== USB (host-side) ==
   enumerated:   True
   usbtmc kmod:  not loaded (good)
   lsof:         no holders

== J-Link / debug probe ==
   backend:        jlink
   jlink software: installed
   probe enum:     True
   probe visible:  True  (emus: J-Link/50105878)
   holders:        none
   gdbserver:      running=False pid=None log_ok=None
   connect:        ok=True class=ok VTref=3.300V core=Cortex-M4

Classification: HEALTHY: J-Link connected to NRF52840_XXAA (Cortex-M4, VTref=3.300V).
A locked target surfaces clearly so you reach for the right recovery:
Classification: TARGET LOCKED: debug access is blocked by readout/IDCODE/AP
protection. A mass-erase/unlock is required (e.g. `nrfjprog --recover` for nRF,
or the vendor unlock flow).

Backwards compatibility

Against a pre-0.20 box, each endpoint returns 404 and the CLI notes that the section is unavailable (the box may be on a lager < 0.20 image). The remaining sections still run — lager diagnose is useful against an older box, just less informative.

See Also

  • Instruments — list attached instruments and their VISA addresses
  • Nets — list saved nets and their roles
  • Debug — connect, flash, and gdbserver control for debug nets
  • Hello — basic box-side connectivity and version check