Upgrade Notes
Two behaviour changes in this release affect code that already works. Neither is caught at install time.DebugNet.connect(script=...)now raises on an OpenOCD debug net when handed a J-Link script. It used to accept the argument and silently ignore it, so a script written for one backend ran the target under whatever attach sequence the net already had. The argument now works on both backends — it is classified by file format and routed — but a.JLinkScriptgiven to an OpenOCD net is aValueErrorrather than a silent no-op. If an automated run passes a.JLinkScriptin-process to a net whose probe uses OpenOCD, pass a.cfginstead, or name the format explicitly withopenocd_config=/jlink_script=. Thelager debugCLI is unaffected; it has always routed by file extension.- Persisted FTDI GPIO output state resets once on upgrade. The state a Lager Box remembers between separate CLI invocations is now keyed by interface as well as device, so that two channels of one multi-channel adapter stop sharing an entry. Existing entries do not carry an interface and are not read back. The first read of a pin after upgrading reports no remembered state; setting it once restores normal behaviour.
Features
DebugNet.halt()stops the target where it is, without a reset. OpenOCD only.reset(halt=True)runs OpenOCD’sreset halt, which pulses nRESET and re-enters through the reset vector; on a part that executes in place out of external QSPI that re-runs the bootloader rather than stopping on the image just programmed.halt()issues a bare halt, so execute-in-place memory still holds what was written. J-Link has no standalone halt-in-place primitive, so on that backend the call raises and names the halt-first.JLinkScriptas the supported route.connect()acceptshalt,openocd_configandjlink_script.haltrunsreset haltonce the daemon is up, and is documented as the reset-then-halt operation it is. The two script arguments are the unambiguous per-backend forms ofscript, for a base64 blob that carries no filename to classify.- FTDI GPIO, I2C and SPI nets can address a specific channel on a multi-channel adapter. A net may now carry
params.interface, takingA-Dor0-3— the same vocabulary debug nets already accept as the@Asuffix on their device field. Which channels are legal is enforced per net: I2C and SPI are MPSSE protocols and on an FT4232H only channels A and B have an MPSSE engine, while GPIO runs as asynchronous bitbang and works on all four.FTDI_FT4232Haccordingly gains thespi,i2candgpioroles its siblings already advertised.
Bug Fixes
DebugNet.connect(script=...)was ignored under the OpenOCD backend. No error, no warning, no log line: the script was written to disk and then never read, because only the J-Link path passed it downstream. A caller supplying a per-run attach script in-process — the way an automated run avoids mutating shared Lager Box state — got a run that silently used whatever attach sequence the net already had. The argument is now classified by extension, then by content, and routed to whichever backend it is for. Per-connect overrides are written to a per-net path rather than the box-wide config file, anddisconnectclears them, so one session’s override cannot reach another net.gpio,i2candspinets on an FT2232H could not be opened. The instrument has advertised all three roles for as long as the role table has existed, solager nets addaccepted them; but the drivers addressed the device by a product selector that matches only the FT232H, so every such net failed to find its hardware. The part is now selected from the USB product ID already present in the net’s own address.- An FTDI net whose address was written as a full
ftdi://URL had it silently discarded. The address was recognised as “not a serial number” and then dropped, with a default URL rebuilt over the top, so a user who spelled out exactly which device and channel they wanted got the first channel of the first FT232H instead. Such an address is now used verbatim. - A box deployed from a branch now says so. After
lager update --version <branch>, nothing on the box recorded which ref produced the code: the version file holds a version number, and a branch not yet bumped past the last release serialises to the same string as the release tag.lager helloreported the release version and a box running a branch was indistinguishable from one on the release tag. The deployed ref is now recorded andlager helloprints it, flagged when it is not a release build. /etc/lager/refwas never written when the box was already up to date. The write sat on the path taken by an update that actually pulled; a run that found the box already at the target version exited before reaching it. That is the case the file matters most in, and because the way to confirm a branch deploy took is thatlager hellonames a ref, its absence reported failure for a deploy that had succeeded.- “SSH key not configured for this box” on a box where the key was installed and working. The check that asks a box whether it has the key did not offer that key to the connection carrying the question, so on a machine whose default credentials the box does not accept it could not authenticate to ask, and reported the key missing on a box it was perfectly able to answer for. It now offers the key explicitly, which widens the credentials tried rather than narrowing them.
Improvements
DebugNet.connect(script=...)now documents that an OpenOCD override must be a complete config rather than a fragment: the launch line still carries lager’s own channel-selection command, which is not recognised unless a config has selected the FTDI adapter driver.
Known Limitations
- OpenOCD debug operations return an empty string where J-Link returns programmer output. A test harness that decides pass or fail by scanning the output of
erase()orflash()for failure markers finds none in an empty string and reads that as success. Against an OpenOCD net, check the target’s state directly rather than parsing the return value.

