Adds the modjam package: a MeshCore-backed test station service for Pi (IDLE + RUNNING states, cuesheet-driven), a control station REPL for the Mac, and a UDP simulator that swaps in for the radio when SIMULATOR=true (drops cross-config packets and a configurable fraction of test-payload datagrams to mimic real radio loss). docker-compose runs three sim stations + control on a bridge net. TSV log format matches the reference traces. Pytest suite covers protocol codec, cuesheet builder, TSV logger, config loader, and UDP radio packet routing/loss; .forgejo/workflows runs it on push to main and on PRs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
93 lines
3.4 KiB
Markdown
93 lines
3.4 KiB
Markdown
# mesh-control
|
|
|
|
Operator quickstart for the LoRa modulation jam test framework. Protocol/spec lives in [reference/concept.md](reference/concept.md).
|
|
|
|
## Components
|
|
|
|
- `modjam-station` — runs on each Test Station (Raspberry Pi or simulator container) talking to a MeshCore node over USB serial.
|
|
- `modjam-control` — interactive REPL on the macbook (or simulator container) that sends START/STOP commands.
|
|
- Simulator — `docker compose` with three test stations (A, B, C) and one control container, swapping the radio for UDP.
|
|
|
|
## Install (host: Pi or Mac)
|
|
|
|
```sh
|
|
python3.11 -m venv .venv && source .venv/bin/activate
|
|
pip install -e .
|
|
```
|
|
|
|
Drop a config at `~/modjam-config.json`. Use [sim/station-a.json](sim/station-a.json) as a template; add `"port": "/dev/ttyUSB0"` (Pi) or `"/dev/tty.usbmodem1301"` (Mac) for the attached MeshCore node.
|
|
|
|
Run:
|
|
|
|
```sh
|
|
modjam-station # on each Pi
|
|
modjam-control # on the Mac
|
|
```
|
|
|
|
## Simulator
|
|
|
|
Three stations + control, no hardware:
|
|
|
|
```sh
|
|
docker compose build
|
|
docker compose up -d station-a station-b station-c
|
|
docker compose run --rm control
|
|
```
|
|
|
|
Inside the control REPL:
|
|
|
|
```
|
|
> start name=sim1 stations=A,B,C bw=500 sf=8 cr=5 pow=22 duration=20 padding=10 spacing=2 size=40 at=1
|
|
> stop
|
|
> quit
|
|
```
|
|
|
|
TSV logs appear in `./sim/logs/` (one per station per run, format matches [reference/A.tsv](reference/A.tsv) / [reference/B.tsv](reference/B.tsv)).
|
|
|
|
`SIMULATOR=true` is what flips the radio backend from MeshCore-USB to UDP. The UDP backend drops cross-config datagrams, so receivers only "hear" senders whose freq/bw/sf/cr/channel match — same behavior as real radios.
|
|
|
|
The simulator also drops a fraction of received **test packets** at random to mimic real-world packet loss. Default is 15%; override with `SIM_PACKET_LOSS=0.0` (no loss) up to `1.0`. Protocol traffic (START/STOP, heartbeats, next/done) is never dropped — only payloads matching the test-packet pattern. Each station gets a deterministic per-station RNG seed so reruns are repeatable; set `SIM_SEED=...` to vary.
|
|
|
|
```sh
|
|
SIM_PACKET_LOSS=0.3 docker compose up -d station-a station-b station-c
|
|
```
|
|
|
|
## REPL commands
|
|
|
|
| Command | Effect |
|
|
|---|---|
|
|
| `start [k=v ...]` | encode and broadcast a START command (see [reference/concept.md](reference/concept.md) for keys: `name`, `f`, `bw`, `sf`, `cr`, `pow`, `size`, `stations`, `duration`, `padding`, `spacing`, `at`) |
|
|
| `stop` | multicast STOP — running stations return to IDLE |
|
|
| `help` | show command list |
|
|
| `quit` | exit |
|
|
|
|
## Layout
|
|
|
|
```
|
|
modjam/
|
|
├── cli.py # entrypoints
|
|
├── config.py # ~/modjam-config.json loader
|
|
├── protocol.py # `<cmd>[:<station>]|k:v,…` codec + heartbeat/next/done formatters
|
|
├── cuesheet.py # build cuesheet from START params
|
|
├── station.py # IDLE/RUNNING state machine
|
|
├── control.py # REPL + rx tail
|
|
├── log.py # TSV logger
|
|
└── radio/
|
|
├── base.py # Radio ABC
|
|
├── meshcore.py # MeshCore over USB serial
|
|
├── udp.py # simulator radio
|
|
└── factory.py # picks backend from SIMULATOR env
|
|
```
|
|
|
|
## Tests
|
|
|
|
```sh
|
|
pip install -e '.[test]'
|
|
pytest
|
|
```
|
|
|
|
CI runs the same suite via [.forgejo/workflows/test.yml](.forgejo/workflows/test.yml) on push to `main` and on PRs.
|
|
|
|
## Scope
|
|
|
|
v1: IDLE + RUNNING only. RESULTS / DOWNLINKING is not implemented yet (see [reference/concept.md](reference/concept.md) and [notes.md](notes.md) for the protocol).
|