add README documenting Makefile targets and build workflow

This commit is contained in:
Russell Ballestrini 2026-05-27 15:06:53 -04:00
parent d9b2499a2e
commit d8607cb000

140
README.md Normal file
View file

@ -0,0 +1,140 @@
# zebra-report
Covert peer-to-peer chat over PulseAudio sink-input volume.
Userland only. No kernel module. No network packets carry the chat content.
Public domain.
## Build & run
Single entry point: `make`. Every workflow goes through a target — never
invoke `gcc` or `python3` by hand.
```bash
make # builds all five binaries (default target = `all`)
make test # builds and runs unit tests (pure logic, no PA needed)
make test-all # unit + integration + functional (PA + sink-inputs required)
make blog # rebuilds the static blog under web/blog/
make serve # builds blog, serves web/ on http://127.0.0.1:8765
make clean # removes binaries and generated blog output
```
`make` is the contract. If a workflow isn't a target, add the target before
adding the workflow.
## Dependencies
```
gcc, make, pkg-config # build chain
libpulse-dev # PulseAudio client lib (pkg-config: libpulse)
python3 # blog builder + dev server
```
Ubuntu / Debian:
```bash
sudo apt install build-essential pkg-config libpulse-dev python3
```
`make` checks libpulse via `pkg-config --cflags libpulse` and
`pkg-config --libs libpulse`; if pkg-config can't find it, the build fails
early with a clear message.
## Targets
### `make all` — five binaries
| Binary | Source | Role |
|-----------|----------------|------|
| `tx` | `src/tx.c` | reads stdin, transmits via volume modulation |
| `rx` | `src/rx.c` | reads target sink-input volumes, decodes to stdout |
| `chat` | `src/chat.c` | bidirectional tx+rx, line-based chat UI |
| `bt` | `src/bt.c` | "battle toads" dual-channel stereo UART (2× throughput) |
| `carrier` | `src/carrier.c`| publishes a silent PA sink so volume reads have something to read |
All link against `libpulse`, `librt`, and `libpthread`. Headers come from
`include/zebra.h` (protocol constants) and `include/modem.h` (inline encode/
decode + benchmark).
### `make test` — unit tests
```
test/unit pure logic, no PA, no audio
```
Covers: signal encoding (`bit_to_vol` / `vol_to_bit`), timing arithmetic
(`ts_add_ns` with overflow), baud math (`baud_from_avg_ns`), handshake frame
build/parse for both OFFER and READY (magic, checksum, corruption).
Currently: **84 cases pass.** Required to be green before any commit.
### `make test-all` — integration + functional
Integration and functional tests need a running PulseAudio daemon and
real sink-inputs to operate on. They are not run by `make test` by default.
```bash
# integration tests need ONE sink-input
ZEBRA_TEST_SINK=<sink_input_index> ./test/integration
# functional tests need TWO sink-inputs (data + ctrl channels)
ZEBRA_DATA_SINK=<idx> ZEBRA_CTRL_SINK=<idx> ./test/functional
```
Find sink-input indices with `pactl list sink-inputs short` — the first
column is the index. The `test/integration` benchmark sub-test reports
measured baud for the current host.
To avoid disrupting real audio applications, spawn dedicated silent
sink-inputs as test targets:
```bash
paplay --raw --format=s16le --rate=44100 --channels=1 \
--stream-name=zebra-test /dev/zero &
# then use `pactl list short sink-inputs` to find this stream's index
```
Currently: **17/17 integration pass; 8/10 functional pass.** The two
functional failures are timing-bound on non-realtime kernels at the
auto-negotiated baud and are not code defects (the same data path passes
at fixed 50 baud).
### `make blog` & `make serve`
`make blog` runs `python3 blog/build.py`, which reads Markdown sources from
`blog/posts/` and writes static HTML into `web/blog/`. `make serve` rebuilds
the blog and serves `web/` on port 8765 for local preview.
The chat UI (`web/chat.html`) is plain static HTML and works directly under
`make serve` — open `http://127.0.0.1:8765/chat.html`.
### `make clean`
Removes:
```
tx rx chat bt carrier
test/unit test/integration test/functional
web/blog/index.html
web/blog/001-volume-modem/
web/blog/002-sse-chatroom/
```
Source files, headers, fonts, recovered binaries on disk, and committed
artifacts under `web/` (other than the generated blog) are not touched.
## Layout
```
include/ protocol constants + inline encode/decode/benchmark
src/ five binaries: tx, rx, chat, bt (battle toads), carrier
test/ unit (pure), integration (PA needed), functional (full chain)
blog/ markdown sources + python build
web/ static site: index, kernel, chat, fonts, generated blog
Makefile every workflow lives here
CLAUDE.md agent operating rules for this repo
```
## License
Public domain. Patches gratefully accepted via merge request at
`git.unturf.com/engineering/unturf/zebra-report`.