Files
DigiRadio/CONTRIBUTING.md
T
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

5.2 KiB
Raw Blame History

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; 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):

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):

idf.py set-target esp32s3
idf.py build
idf.py erase-flash flash monitor

Host unit tests (pure core, no hardware):

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/):

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), 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.