Files
DigiRadio/CONTRIBUTING.md
micheleandCursor 8439ec4055 Sync all project docs for firmware 0.8.3 completion.
Update READMEs, manual chapters, agent guides, CONTRIBUTING, and TODO to reflect T1–T8 done, encrypted NVS, CI gates, and pending HIL checklist.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 07:49:07 +02:00

138 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Contributing to DigiRadio
Thanks for your interest in DigiRadio. This document covers the firmware
development conventions. The full, authoritative rules live in
[`Software/AGENTS.md`](Software/AGENTS.md); this is the human-facing
summary.
**Current firmware:** **0.8.3** on `main` — agent tasks T1T8 complete;
device HIL pending first PCB.
DigiRadio is dual-licensed: hardware under **CERN-OHL-S v2**, firmware
under **Apache-2.0**. By contributing, you agree your contributions are
licensed under the same terms as the part of the project they touch.
## Toolchain
| Item | Choice |
|-----------|------------------------------------------|
| Framework | ESP-IDF v5.5.x (native, not Arduino) |
| Language | C++23, pinned `-std=gnu++23` |
| Errors | `std::expected<T, Error>`; exceptions off|
| Security | NVS + flash encryption (dev mode) |
| Docs | Doxygen + LaTeX manual sync (CI enforced)|
On macOS, the host unit tests need a C++23 standard library: use
Homebrew `llvm` (>= 18) or `gcc-14`, not the system Apple Clang.
## Build, test, docs
Si4684 blobs (local only, not in git):
```bash
cd Software
python3 tools/fetch_si4684_firmware.py --dab-only
python3 tools/fetch_si4684_firmware.py --si46xx-dir /path/to/si46xx_firmware
```
Device build / flash / monitor (first encrypted flash: include `erase-flash`):
```bash
idf.py set-target esp32s3
idf.py build
idf.py erase-flash flash monitor
```
Host unit tests (pure core, no hardware):
```bash
cmake -S components/core/test -B build-host \
-DCMAKE_CXX_COMPILER="$(brew --prefix llvm)/bin/clang++"
cmake --build build-host
ctest --test-dir build-host --output-on-failure
```
Documentation and policy checks (must exit 0; run from `Software/`):
```bash
doxygen Doxyfile
python3 tools/check-manual-sync.py
python3 tools/check_si4684_blobs.py
```
After editing the web UI: `python3 tools/gzip-www.sh`.
The LaTeX manual lives in `Software/docs/manual/` (canonical). Design and
HTTP JSON API: `ch-api.tex`; security: `docs/security-flash-nvs.md`.
Rebuild the PDF with `latexmk -lualatex manual.tex` inside
`Software/docs/manual/`.
## Coding conventions
The guiding idea is *Code That Fits in Your Head*: code must fit in
human working memory at every zoom level.
- **Complexity `<= 7`** per method; **methods fit an 80x24 box** (<= 80
columns, <= 24 lines). One method does one thing.
- **Strong typing.** No primitive obsession: domain quantities are their
own types. `enum class` always; no booleans for mode selection.
Validate untrusted input once at the boundary.
- **RAII and `const` by default.** Wrap every hardware/OS handle; no raw
`new`/`delete`; borrow with `std::span`, not pointer + length.
- **Functional core, imperative shell.** Pure logic in
`components/core` (no ESP-IDF headers, host-tested); hardware access in
the shell.
- **No silent failure.** Fallible operations return `std::expected`;
every timeout is an explicit error.
- **Embedded discipline.** No dynamic allocation in audio or ISR paths;
no virtual calls in IRAM-safe ISRs; every wait has a timeout.
- **Never invent** a register address, opcode, or boot sequence — cite
the datasheet section in a comment, or stop and ask.
## File headers and documentation
Every source file starts with the Apache-2.0 header (see
[`Software/apache-header.txt`](Software/apache-header.txt)), with
`@file`, `@author`, and `@date` filled in.
Every class and method carries a Doxygen block with, in order: name
(`@dname`), parameters (`@param`), return (`@return`), public state used
(`@pubstate`), a description of intent (not a restatement of the code),
and `@author` / `@date`. The `doxygen Doxyfile` build enforces this —
an undocumented symbol fails the build.
## Commits and pull requests
- **Small, focused commits.** Each commit compiles and keeps host tests
green. One logical change per commit.
- **Commit messages: 50/72.** Summary line <= 50 characters, imperative
mood; blank line; body wrapped at 72 explaining *why*.
- Keep `main` always building. Use feature branches for work in
progress; no commented-out code in commits.
## Definition of Done
Before opening a PR, confirm:
- [ ] Compiles with warnings-as-errors; clang-tidy clean.
- [ ] Every file has the Apache-2.0 header.
- [ ] Every class and method has its documentation block.
- [ ] `doxygen Doxyfile` exits 0 with an empty warnings log.
- [ ] `python3 tools/check-manual-sync.py` passes.
- [ ] `python3 tools/check_si4684_blobs.py` passes.
- [ ] Manual updated: `ch-classes.tex` for new/changed public classes;
`ch-api.tex` for new/changed HTTP endpoints.
- [ ] Every method fits 80x24 and complexity <= 7.
- [ ] Fallible paths return typed results; no silent failure.
- [ ] Pure-core logic has passing host unit tests.
- [ ] No secret is loggable or stored in plaintext.
- [ ] Register-level decisions cite the datasheet section.
- [ ] No dynamic allocation in audio/ISR paths.
- [ ] Web UI changes regenerate `index.html.gz` via `tools/gzip-www.sh`.
## Editor setup (optional)
The repository ships Cursor rules under `Software/.cursor/rules/`. If you
use Cursor, open the `Software/` directory as the project so the rules
and `AGENTS.md` are picked up automatically.