diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6a7344a --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# Build outputs +*.o +mwcli +mw_controller_example + +# Logs and captures +*.csv +*.log + +# Editors / OS +*~ +.DS_Store diff --git a/HELP.md b/HELP.md new file mode 100644 index 0000000..0eead04 --- /dev/null +++ b/HELP.md @@ -0,0 +1,671 @@ +# MightyWatt Linux CLI Help + +This document matches the current backend/CLI tree in this repository. + +## Scope + +Current features: +- serial communication with MightyWatt hardware +- reusable C backend (`libmightywatt_core` style project layout) +- CLI control and monitoring +- CSV logging +- JSON-driven sequence runner +- loops in the sequence engine +- mandatory `abort_sequence` for safe shutdown / cleanup + +Current sequence format: +- **JSON only** +- YAML is **not** supported in the current C implementation + +--- + +## General usage + +```bash +mwcli -d /dev/ttyACM0 [global options] [command args] +``` + +Example: + +```bash +./mwcli -d /dev/ttyACM0 caps +``` + +--- + +## Global options + +These options go before the command. + +### `-d, --device PATH` +Serial device path. + +Example: + +```bash +./mwcli -d /dev/ttyACM0 caps +``` + +### `-s, --settle-ms N` +Delay after opening the serial port, in milliseconds. + +Default: + +```text +2200 +``` + +Use this because Arduino-class boards often reset when the port is opened. + +Example: + +```bash +./mwcli -d /dev/ttyACM0 -s 2500 caps +``` + +### `-i, --interval-ms N` +Polling interval in milliseconds. + +Used by: +- `monitor` +- `hold` + +Default: + +```text +500 +``` + +### `-c, --count N` +Number of samples. + +Used by: +- `monitor` +- `hold` + +If omitted, the stream continues until interrupted with `Ctrl+C`. + +### `--sample-period-ms N` +Override `sample_period_ms` from the JSON sequence file. + +Used by: +- `run-sequence` + +### `--csv PATH` +Write measurement samples to a CSV file. + +Works with: +- `report` +- `monitor` +- `hold` +- `load-on` +- `load-off` +- `safe` +- `remote` +- `set-*` +- `run-sequence` + +### `-j, --json` +Print JSON to stdout instead of plain text. + +Useful for: +- scripts +- wrappers +- future GUI integration + +Current behaviour: +- one-shot commands print one JSON object +- `monitor` and `hold` print JSON lines +- `run-sequence` prints one summary object at the end + +### `-h, --help` +Show built-in CLI help. + +--- + +# Commands + +## `idn` +Query the device identity string. + +## `caps` +Read device capabilities. + +Typical fields: +- firmware version +- board revision +- max current DAC / ADC +- max voltage DAC / ADC +- max power +- DVM input resistance +- temperature threshold + +## `report` +Read one measurement report. + +Returns: +- current +- voltage +- power +- temperature +- remote state +- status + +## `monitor` +Continuously poll and print measurements. + +Examples: + +```bash +./mwcli -d /dev/ttyACM0 monitor +./mwcli -d /dev/ttyACM0 -i 500 -c 20 monitor +./mwcli -d /dev/ttyACM0 -j monitor +``` + +## `set-current ` +Stage/set current target. + +## `set-voltage ` +Stage/set voltage target. + +## `set-power ` +Stage/set power target. + +## `set-resistance ` +Stage/set resistance target. + +## `set-vinv ` +Stage/set inverted-voltage target. + +This is a firmware-supported special mode. + +## `hold ` +Enable and keep a target alive by polling continuously. + +This is the right command for real bench work because the MightyWatt watchdog requires regular host traffic. + +Modes: +- `current` +- `voltage` +- `power` +- `resistance` +- `vinv` + +Aliases accepted: +- `CC` +- `CV` +- `CP` +- `CR` + +Examples: + +```bash +./mwcli -d /dev/ttyACM0 hold current 0.250 +./mwcli -d /dev/ttyACM0 -i 500 -c 10 hold power 1.000 +./mwcli -d /dev/ttyACM0 -j hold resistance 20.000 +``` + +## `load-on ` +Apply a target once and return one report. + +Important: +- this is a one-shot command +- the hardware may fall back after ~1–2 seconds if no more host traffic follows +- for sustained load use `hold` + +## `load-off` +Turn the load off. + +Current implementation: +- host-side load-off via zero-current target +- the MightyWatt protocol has no dedicated hardware output-enable bit + +## `safe` +Go to safe state. + +Current implementation: +- load off +- remote sense off + +## `remote on|off` +Enable or disable remote sense. + +## `get-series` +Read configured series resistance. + +Output unit: +- ohms + +## `set-series ` +Set series resistance. + +## `run-sequence ` +Run a JSON sequence file. + +Examples: + +```bash +./mwcli -d /dev/ttyACM0 run-sequence profile.json +./mwcli -d /dev/ttyACM0 --csv run.csv run-sequence profile.json +./mwcli -d /dev/ttyACM0 --sample-period-ms 200 run-sequence profile.json +``` + +--- + +# CSV logging + +When `--csv ` is used, the logger writes: + +- `timestamp_utc` +- `elapsed_s` +- `context` +- `step_index` +- `current_a` +- `voltage_v` +- `power_w` +- `temperature_c` +- `remote` +- `status_bits` +- `status_text` + +Example: + +```bash +./mwcli -d /dev/ttyACM0 --csv monitor.csv -c 20 monitor +``` + +--- + +# JSON sequence format + +## Top-level structure + +A sequence file is a JSON object with these top-level keys: + +```json +{ + "name": "example_name", + "sample_period_ms": 500, + "safety": { + "max_voltage": 30.0, + "max_current": 2.0, + "max_power": 20.0, + "abort_on_disconnect": true + }, + "steps": [ + ... + ], + "abort_sequence": [ + { "action": "safe" } + ] +} +``` + +Important: +- `steps` is required and must be non-empty +- `abort_sequence` is required and must be non-empty +- `abort_sequence` runs at the normal end of the main sequence and also after runtime abort/error paths whenever possible + +## Top-level fields + +### `name` +Optional string. + +### `sample_period_ms` +Optional number. + +Default: + +```text +500 +``` + +Purpose: +- polling interval during `hold`, `hold_until`, loops, ramps, and CSV logging + +### `safety` +Optional object. + +Supported fields: +- `max_voltage` in volts +- `max_current` in amps +- `max_power` in watts +- `abort_on_disconnect` boolean + +Practical note: +- the current engine attempts the `abort_sequence` on runtime failures in general +- `abort_on_disconnect` is kept in the profile format for future separation of policies, but is not yet handled as a dedicated branch different from other runtime failures + +### `steps` +Required array. + +### `abort_sequence` +Required array. + +Typical safe form: + +```json +"abort_sequence": [ + { "action": "safe" } +] +``` + +--- + +# Supported actions + +## `set_mode` +Stage the operating mode. + +```json +{ "action": "set_mode", "mode": "CC" } +``` + +Accepted `mode` values: +- `CC` / `current` +- `CV` / `voltage` +- `CP` / `power` +- `CR` / `resistance` +- `CVINV` / `vinv` / `voltage_inverted` + +## `set_current` +```json +{ "action": "set_current", "value": 0.20 } +``` +Unit: amps. + +## `set_voltage` +```json +{ "action": "set_voltage", "value": 4.80 } +``` +Unit: volts. + +## `set_power` +```json +{ "action": "set_power", "value": 2.00 } +``` +Unit: watts. + +## `set_resistance` +```json +{ "action": "set_resistance", "value": 10.0 } +``` +Unit: ohms. + +## `set_vinv` +```json +{ "action": "set_vinv", "value": 4.50 } +``` +Unit: volts. + +## `output` +Enable or disable the staged output. + +```json +{ "action": "output", "enabled": true } +``` + +or + +```json +{ "action": "output", "enabled": false } +``` + +## `hold` +Keep the current staged/active target alive for a duration. + +```json +{ "action": "hold", "duration_s": 30 } +``` + +## `hold_until` +Keep polling until a condition becomes true or timeout is reached. + +```json +{ + "action": "hold_until", + "timeout_s": 300, + "condition": { + "type": "voltage_below", + "value": 3.00 + } +} +``` + +## `ramp_current` +```json +{ + "action": "ramp_current", + "start": 0.20, + "stop": 1.00, + "step": 0.10, + "dwell_s": 20 +} +``` + +## `ramp_voltage` +```json +{ + "action": "ramp_voltage", + "start": 4.0, + "stop": 5.0, + "step": 0.1, + "dwell_s": 10 +} +``` + +## `ramp_power` +```json +{ + "action": "ramp_power", + "start": 0.5, + "stop": 5.0, + "step": 0.5, + "dwell_s": 15 +} +``` + +## `ramp_resistance` +```json +{ + "action": "ramp_resistance", + "start": 100.0, + "stop": 10.0, + "step": 10.0, + "dwell_s": 5 +} +``` + +## `ramp_vinv` +```json +{ + "action": "ramp_vinv", + "start": 4.8, + "stop": 4.0, + "step": 0.1, + "dwell_s": 10 +} +``` + +## `repeat` +Run a nested block a fixed number of times. + +```json +{ + "action": "repeat", + "times": 5, + "steps": [ + { "action": "set_current", "value": 0.20 }, + { "action": "output", "enabled": true }, + { "action": "hold", "duration_s": 10 }, + { "action": "output", "enabled": false }, + { "action": "hold", "duration_s": 5 } + ] +} +``` + +## `repeat_until` +Run a nested block until a condition becomes true. + +```json +{ + "action": "repeat_until", + "timeout_s": 1800, + "condition": { "type": "voltage_below", "value": 3.20 }, + "steps": [ ... ] +} +``` + +Notes: +- the block runs at least once +- `timeout_s` is optional +- if omitted or `0`, the loop is unlimited + +## `repeat_while` +Run a nested block while a condition remains true. + +```json +{ + "action": "repeat_while", + "timeout_s": 7200, + "condition": { "type": "temperature_above", "value": 20.0 }, + "steps": [ ... ] +} +``` + +Notes: +- the condition is checked before each iteration +- `timeout_s` is optional +- if omitted or `0`, the loop is unlimited + +## `safe` +Immediate safe-state action. + +```json +{ "action": "safe" } +``` + +## `remote` +Set remote sense on or off. + +```json +{ "action": "remote", "enabled": true } +``` + +--- + +# Conditions + +Supported condition types: +- `voltage_below` +- `voltage_above` +- `current_below` +- `current_above` +- `power_below` +- `power_above` +- `temperature_above` + +Units: +- voltage conditions: volts +- current conditions: amps +- power conditions: watts +- temperature condition: °C + +--- + +# `break_if` + +Any step can carry an optional `break_if` object. + +Format: + +```json +"break_if": { + "type": "temperature_above", + "value": 45.0 +} +``` + +Behaviour: +- `break_if` is checked whenever a report is read during that step +- on block steps like `repeat`, `repeat_until`, or `repeat_while`, the `break_if` stays active for the whole nested block +- if `break_if` becomes true, the main sequence stops and the mandatory `abort_sequence` starts + +Typical use: +- thermal guard during long tests +- abort if measured voltage/current/power crosses a forbidden threshold + +--- + +# Sequence execution model + +Recommended staging pattern: + +1. `set_mode` +2. `set_current` / `set_voltage` / `set_power` / `set_resistance` / `set_vinv` +3. `output true` +4. `hold`, `hold_until`, `ramp_*`, or loop block +5. `output false` or rely on `abort_sequence` + +Important: +- the MightyWatt watchdog requires regular host traffic +- `hold`, `hold_until`, ramps, and loop checks all provide that traffic +- a plain one-shot `output true` step with no later polling logic is not suitable for long unattended operation + +--- + +# Example sequence with loop and safe abort + +```json +{ + "name": "repeat_until_cutoff", + "sample_period_ms": 1000, + "safety": { + "max_voltage": 5.0, + "max_current": 0.6, + "max_power": 3.0, + "abort_on_disconnect": true + }, + "steps": [ + { "action": "set_mode", "mode": "CC" }, + { + "action": "repeat_until", + "timeout_s": 14400, + "condition": { "type": "voltage_below", "value": 3.20 }, + "break_if": { "type": "temperature_above", "value": 45.0 }, + "steps": [ + { "action": "set_current", "value": 0.30 }, + { "action": "output", "enabled": true }, + { "action": "hold", "duration_s": 60 }, + { "action": "output", "enabled": false }, + { "action": "hold", "duration_s": 10 } + ] + } + ], + "abort_sequence": [ + { "action": "safe" } + ] +} +``` + +Run it with: + +```bash +./mwcli -d /dev/ttyACM0 --csv run.csv run-sequence repeat_until_cutoff.json +``` + +--- + +# Practical notes + +- Use `hold` or `run-sequence` for anything longer than a quick manual check. +- Use `--csv` whenever the data matters. +- Keep `abort_sequence` simple and safe. +- Start with conservative limits. +- `set-vinv` / `ramp_vinv` are advanced functions. +- Loop timing in practice is affected by serial round-trip time and sample period; do not expect hard real-time behaviour. + + +## CSV raw mode + +Use `--csv-raw` together with `--csv ` to write elapsed time in **ms** and electrical values in **mA / mV / mW**. This is useful for spreadsheet tools that handle decimal separators poorly. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3cd66a9 --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +CC ?= gcc +CFLAGS ?= -O2 -Wall -Wextra -Wpedantic -std=c11 +CPPFLAGS ?= -D_POSIX_C_SOURCE=200809L -Iinclude +THREAD_FLAGS ?= -pthread +LDFLAGS ?= + +OBJ = src/mightywatt.o src/mightywatt_app.o src/mightywatt_controller.o src/mightywatt_log.o src/mightywatt_sequence.o src/mwcli.o +BIN = mwcli +EXAMPLE_BIN = mw_controller_example + +all: $(BIN) $(EXAMPLE_BIN) + +$(BIN): $(OBJ) + $(CC) $(CFLAGS) $(THREAD_FLAGS) $(OBJ) -o $@ $(LDFLAGS) + +$(EXAMPLE_BIN): src/mightywatt.o src/mightywatt_app.o src/mightywatt_controller.o examples/mw_controller_example.o + $(CC) $(CFLAGS) $(THREAD_FLAGS) $^ -o $@ $(LDFLAGS) + +src/%.o: src/%.c include/*.h + $(CC) $(CPPFLAGS) $(CFLAGS) $(THREAD_FLAGS) -c $< -o $@ + +examples/%.o: examples/%.c include/*.h + $(CC) $(CPPFLAGS) $(CFLAGS) $(THREAD_FLAGS) -c $< -o $@ + +clean: + rm -f $(OBJ) examples/*.o $(BIN) $(EXAMPLE_BIN) + +.PHONY: all clean diff --git a/NOTICE.md b/NOTICE.md new file mode 100644 index 0000000..689751a --- /dev/null +++ b/NOTICE.md @@ -0,0 +1,33 @@ +# NOTICE / Attribution + +## This project + +**0005-DenryokuBancho / 電力番長 (Denryoku Banchō)** is a Linux-native CLI fork built to control and automate MightyWatt hardware from Linux. + +Its focus is: +- headless operation +- automation pipelines +- CSV logging +- JSON-driven test sequences +- lean deployment on SBC hardware + +## Upstream project and credit + +This work is based on the original **MightyWatt** project by **Jakub Polonský** (`kaktus85`). + +Jakub created the original MightyWatt hardware design and the original software resources, including the Arduino sketches and Windows control program. + +Original upstream repository: +- https://github.com/kaktus85/MightyWatt + +## Thanks + +Many thanks to **Jakub Polonský / `kaktus85`** for designing and publishing the original MightyWatt hardware and software. + +This Linux-native fork exists because the original project is good enough to deserve a practical Linux control and automation path. + +## License note + +This repository is prepared under the **GNU GPL v3**. + +Please review the original upstream repository for the exact licensing structure of the original MightyWatt project contents. diff --git a/README.md b/README.md index 65f7533..7db64ac 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,241 @@ -# 0005-DenryokuBancho +# 0005-DenryokuBancho / 電力番長 (Denryoku Banchō) -電力番長 (Denryoku Banchō) is a Linux-native CLI fork of the MightyWatt electronic load project by Jakub Polonský (kaktus85). Focused on headless operation, automation pipelines, CSV logging, and JSON-driven test sequences — built to run lean on SBC hardware. \ No newline at end of file +電力番長 (Denryoku Banchō) is a Linux-native CLI fork of the MightyWatt electronic load project by Jakub Polonský (`kaktus85`). It is focused on headless operation, automation pipelines, CSV logging, and JSON-driven test sequences, built to run lean on SBC hardware. + +This repository is intentionally backend-first. The goal is to provide a practical Linux control and automation path for MightyWatt hardware before building a GTK frontend on top of it. + +--- + +## Attribution and upstream + +This project builds on the original **MightyWatt** work by **Jakub Polonský** (`kaktus85`) back in 2014 to 2017. I own on MightyWatt since 2016. + +Jakub designed the MightyWatt hardware and created the original Arduino firmware and Windows control program. Many thanks to him for publishing such a useful open hardware / software project. + +Original upstream project: +- [GitHub - MightyWatt](https://github.com/kaktus85/MightyWatt) +- [KaktusCircuits Blog Entry](https://kaktuscircuits.blogspot.com/2014/02/mightywatt-arduino-electronic-load.html) +- [Archive.Org - Blog Entry](https://web.archive.org/web/20260101000000*/https://kaktuscircuits.blogspot.com/2014/02/mightywatt-arduino-electronic-load.html) + +Please also see: +- `NOTICE.md` +- `LICENSE` + +--- + +## Current release status + +### Beta 0.1 - Scope: + +This beta provides a usable Linux-native backend and CLI for real MightyWatt hardware, with emphasis on: + +- serial communication from Linux +- headless bench operation +- watchdog-safe sustained load control +- CSV logging +- raw CSV export for spreadsheet workflows +- JSON-driven automated test sequences +- loop-based sequence execution for repeated test patterns + +### Already validated on real my real hardware + +- device identification and capability query +- measurement readout +- manual CLI control +- watchdog-safe `hold` operation +- CSV logging +- sequence execution on real hardware +- raw CSV export mode + +### Implemented but still beta-level + +- `repeat` +- `repeat_until` +- `repeat_while` +- inherited `break_if` +- mandatory `abort_sequence` +- nested sequence blocks +- controller/backend layering for later GUI reuse + +The backend is useful now, but the sequence engine should still be treated as bench-validated step by step, not as a finished production automation framework. + +### Deliberately not the focus of this release + +- GTK4 frontend +- persistent settings store +- profile editor GUI +- plotting GUI + +--- + +## Repository layout + +```text +include/ + mightywatt.h + mightywatt_app.h + mightywatt_controller.h + mightywatt_log.h + mightywatt_sequence.h + +src/ + mightywatt.c low-level protocol + serial transport + mightywatt_app.c synchronous backend layer + mightywatt_controller.c long-running controller/polling layer + mightywatt_log.c CSV logger + mightywatt_sequence.c JSON sequence engine + mwcli.c CLI frontend + +examples/ + *.json sequence examples + mw_controller_example.c controller example +``` + +### Layering + +- `mightywatt.c` = raw device communication +- `mightywatt_app.c` = safe synchronous operations +- `mightywatt_controller.c` = GUI-ready async/controller layer +- `mightywatt_sequence.c` = reusable sequence engine on top of the backend +- `mwcli.c` = thin user-facing CLI + +This keeps a future GTK frontend from reimplementing protocol or automation logic. + +--- + +## Build + +Requirements: +- Linux +- GCC or Clang +- POSIX serial/thread support +- no external runtime dependencies for the current CLI/backend build + +Build: + +```bash +make +``` + +This builds: +- `mwcli` +- `mw_controller_example` + +--- + +## Typical CLI usage + +Read capabilities: + +```bash +./mwcli -d /dev/ttyACM0 caps +``` + +Read one measurement: + +```bash +./mwcli -d /dev/ttyACM0 report +``` + +Hold a constant current safely against the watchdog: + +```bash +./mwcli -d /dev/ttyACM0 hold current 0.250 --interval-ms 500 +``` + +Run a sequence and log CSV: + +```bash +./mwcli -d /dev/ttyACM0 --csv run.csv run-sequence examples/quick_cc_test.json +``` + +Run a sequence with raw CSV output for spreadsheet import: + +```bash +./mwcli -d /dev/ttyACM0 --csv run_raw.csv --csv-raw run-sequence examples/repeat_until_cutoff.json +``` + +--- + +## Sequence engine overview + +Current sequence engine features: +- linear step execution +- `hold` +- `hold_until` +- ramps +- `repeat` +- `repeat_until` +- `repeat_while` +- per-step and per-block `break_if` +- mandatory `abort_sequence` +- CSV logging during polling/report events + +The format is **JSON only** in the current implementation. + +See: +- `HELP.md` +- `sequence_examples.md` +- `examples/*.json` + +--- + +## Safety model + +There are three layers of protection: + +1. **Sequence safety limits** + - max voltage + - max current + - max power + +2. **`break_if` conditions** + - especially useful for thermal guard behaviour + - also usable for voltage/current/power-based aborts + +3. **Mandatory `abort_sequence`** + - runs at the normal end of a sequence + - also runs after runtime abort paths whenever possible + - should usually contain at least: + +```json +"abort_sequence": [ + { "action": "safe" } +] +``` + +Practical note: +- if the serial/device link is already gone, the backend will still attempt the abort sequence, but that can of course fail physically + +--- + +## Documentation files + +- `HELP.md` — CLI help and full JSON format reference +- `sequence_examples.md` — practical example overview +- `examples/*.json` — ready-to-edit starting profiles +- `NOTICE.md` — attribution and upstream note + +--- + +## Known limitations + +- no YAML parser yet +- no `validate-sequence` or dry-run command yet +- no explicit boolean condition combiner (`AND` / `OR`) yet +- no profile include/import system +- no persistence layer for CLI settings +- no active GUI in this beta release +- loop timing is not hard real-time; it depends on polling interval and serial turnaround + +Also important: +- `sample_period_ms` is the visible/logging interval, not the low-level keepalive interval +- loop-heavy profiles should still be validated carefully on the bench before trusting them unattended + +--- + +## License + +This repository is released under the [**GNU GPL v3**](https://www.gnu.org/licenses/gpl-3.0.en.html). + +The original upstream MightyWatt repository contains its own license files for its original contents. Review the upstream repository for the exact license structure of the original project components. \ No newline at end of file diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..f208c66 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1-beta diff --git a/sequence_examples.md b/sequence_examples.md new file mode 100644 index 0000000..cb9ccd6 --- /dev/null +++ b/sequence_examples.md @@ -0,0 +1,162 @@ +# Sequence examples + +These profiles are intended as practical starting points for bench work with the current MightyWatt Linux backend. + +Important: +- all examples use the current **JSON** format +- all examples include the now mandatory `abort_sequence` +- the values are intentionally conservative and should be adjusted to your real DUT and PSU +- these are **bench-ready templates**, not guaranteed universal production recipes + +--- + +## 1. Quick constant-current sanity check + +File: +- `examples/quick_cc_test.json` + +Purpose: +- first proof that the backend, hardware, PSU, and measurement gear agree +- low-risk stepped current check + +Highlights: +- simple linear flow +- ends with `safe` + +Run: + +```bash +./mwcli -d /dev/ttyACM0 --csv quick_cc.csv run-sequence examples/quick_cc_test.json +``` + +--- + +## 2. CC sweep with thermal break guard + +File: +- `examples/cc_step_sweep.json` + +Purpose: +- step/ramp current upward +- stop early if temperature climbs above a chosen limit + +Highlights: +- `ramp_current` +- `break_if` for temperature + +Run: + +```bash +./mwcli -d /dev/ttyACM0 --csv cc_sweep.csv run-sequence examples/cc_step_sweep.json +``` + +--- + +## 3. Fixed-count pulse loop + +File: +- `examples/repeat_n_pulse_test.json` + +Purpose: +- repeat a pulse/rest pattern a defined number of times +- useful for basic cyclic load testing + +Highlights: +- `repeat` +- nested `steps` +- loop-level `break_if` + +Run: + +```bash +./mwcli -d /dev/ttyACM0 --csv pulse_loop.csv run-sequence examples/repeat_n_pulse_test.json +``` + +--- + +## 4. Repeat until voltage cutoff + +File: +- `examples/repeat_until_cutoff.json` + +Purpose: +- run repeated load/rest blocks until the measured voltage falls below a threshold +- suitable for simple discharge-style tests + +Highlights: +- `repeat_until` +- timeout protection +- temperature `break_if` + +Run: + +```bash +./mwcli -d /dev/ttyACM0 --csv until_cutoff.csv run-sequence examples/repeat_until_cutoff.json +``` + +--- + +## 5. Battery discharge cutoff profile + +File: +- `examples/battery_discharge_cutoff.json` + +Purpose: +- continuous constant-current discharge until undervoltage cutoff + +Highlights: +- `hold_until` +- simple thermal guard + +Run: + +```bash +./mwcli -d /dev/ttyACM0 --csv discharge.csv run-sequence examples/battery_discharge_cutoff.json +``` + +--- + +## 6. While-loop burn-in style template + +File: +- `examples/repeat_while_burn_in.json` + +Purpose: +- show the new `repeat_while` block +- keep cycling while a condition remains true + +Highlights: +- `repeat_while` +- optional timeout +- loop-level `break_if` + +Run: + +```bash +./mwcli -d /dev/ttyACM0 --csv burnin.csv run-sequence examples/repeat_while_burn_in.json +``` + +--- + +## Notes on choosing a template + +Use this rough rule: +- short manual comparison against PSU/DMM -> `quick_cc_test.json` +- stepped current sweep -> `cc_step_sweep.json` +- cyclic pulse/load-rest pattern -> `repeat_n_pulse_test.json` +- stop when voltage drops below cutoff -> `repeat_until_cutoff.json` or `battery_discharge_cutoff.json` +- experimental loop based on a live condition -> `repeat_while_burn_in.json` + +--- + +## Safety note + +For unattended or long tests: +- keep the `abort_sequence` simple +- keep thermal `break_if` conservative +- always validate the profile with a short low-power run first + + +## CSV raw mode + +Use `--csv-raw` together with `--csv ` to write elapsed time in **ms** and electrical values in **mA / mV / mW**. This is useful for spreadsheet tools that handle decimal separators poorly.