Beta 0.1 – First Linux CLI/backend release
This commit is contained in:
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Build outputs
|
||||||
|
*.o
|
||||||
|
mwcli
|
||||||
|
mw_controller_example
|
||||||
|
|
||||||
|
# Logs and captures
|
||||||
|
*.csv
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Editors / OS
|
||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
671
HELP.md
Normal file
671
HELP.md
Normal file
@ -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> [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 <amps>`
|
||||||
|
Stage/set current target.
|
||||||
|
|
||||||
|
## `set-voltage <volts>`
|
||||||
|
Stage/set voltage target.
|
||||||
|
|
||||||
|
## `set-power <watts>`
|
||||||
|
Stage/set power target.
|
||||||
|
|
||||||
|
## `set-resistance <ohms>`
|
||||||
|
Stage/set resistance target.
|
||||||
|
|
||||||
|
## `set-vinv <volts>`
|
||||||
|
Stage/set inverted-voltage target.
|
||||||
|
|
||||||
|
This is a firmware-supported special mode.
|
||||||
|
|
||||||
|
## `hold <mode> <value>`
|
||||||
|
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 <mode> <value>`
|
||||||
|
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 <ohms>`
|
||||||
|
Set series resistance.
|
||||||
|
|
||||||
|
## `run-sequence <sequence.json>`
|
||||||
|
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 <file>` 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 <file>` to write elapsed time in **ms** and electrical values in **mA / mV / mW**. This is useful for spreadsheet tools that handle decimal separators poorly.
|
||||||
28
Makefile
Normal file
28
Makefile
Normal file
@ -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
|
||||||
33
NOTICE.md
Normal file
33
NOTICE.md
Normal file
@ -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.
|
||||||
242
README.md
242
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.
|
電力番長 (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.
|
||||||
162
sequence_examples.md
Normal file
162
sequence_examples.md
Normal file
@ -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 <file>` to write elapsed time in **ms** and electrical values in **mA / mV / mW**. This is useful for spreadsheet tools that handle decimal separators poorly.
|
||||||
Reference in New Issue
Block a user