|
Some checks failed
tests / pytest (push) Failing after 9s
This repo was produced primarily by an LLM, so most of it is not eligible for copyright protection to begin with. CC0 covers any portion that turns out to be copyrightable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| docker | ||
| modjam | ||
| reference | ||
| sim | ||
| tests | ||
| .gitignore | ||
| docker-compose.yml | ||
| LICENSE | ||
| notes.md | ||
| pyproject.toml | ||
| README.md | ||
| requirements.txt | ||
mesh-control
Operator quickstart for the LoRa modulation jam test framework. Protocol/spec lives in reference/concept.md.
Authorship & copyright. This repository was produced primarily by a large language model (Claude). LLM-generated output is generally not eligible for copyright in the US and similar jurisdictions, so this code is in the public domain. To the extent any part is copyrightable, it is dedicated to the public domain via CC0 1.0.
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 composewith three test stations (A, B, C) and one control container, swapping the radio for UDP.
Install (host: Pi or Mac)
python3.11 -m venv .venv && source .venv/bin/activate
pip install -e .
Drop a config at ~/modjam-config.json. Use sim/station-a.json as a template; add "port": "/dev/ttyUSB0" (Pi) or "/dev/tty.usbmodem1301" (Mac) for the attached MeshCore node.
Run:
modjam-station # on each Pi
modjam-control # on the Mac
Simulator
Three stations + control, no hardware:
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/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.
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 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
pip install -e '.[test]'
pytest
CI runs the same suite via .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 and notes.md for the protocol).