Enable CI gate: fix Doxygen and add workflow.
Clear doc-block warnings so doxygen exits 0, add GitHub Actions for host tests, Doxygen, and manual sync, and document CI in the manual. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
host-tests:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: Software
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install build tools
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y cmake g++-14
|
||||||
|
- name: Build and run host tests
|
||||||
|
run: |
|
||||||
|
cmake -S components/core/test -B build-host \
|
||||||
|
-DCMAKE_CXX_COMPILER=g++-14
|
||||||
|
cmake --build build-host
|
||||||
|
ctest --test-dir build-host --output-on-failure
|
||||||
|
|
||||||
|
doxygen:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: Software
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install Doxygen
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y doxygen
|
||||||
|
- name: Run Doxygen (fail on warnings)
|
||||||
|
run: doxygen Doxyfile
|
||||||
|
|
||||||
|
manual-sync:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: Software
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Check manual class sync
|
||||||
|
run: python3 tools/check-manual-sync.py --src components --manual docs/manual
|
||||||
@@ -104,7 +104,7 @@ Firmware development backlog and agent tasks:
|
|||||||
- ✅ **PCB layout** — 6-layer, DRC clean, plane continuity verified
|
- ✅ **PCB layout** — 6-layer, DRC clean, plane continuity verified
|
||||||
- ✅ **BOM** — finalised (manufacturable / sourced)
|
- ✅ **BOM** — finalised (manufacturable / sourced)
|
||||||
- 🔜 **Prototype** — in fabrication (PCBWay)
|
- 🔜 **Prototype** — in fabrication (PCBWay)
|
||||||
- 🛠️ **Firmware** — fw 0.7.0 on `main` (tuner, DSP, BT pairing, presets); see [`Software/docs/TODO.md`](Software/docs/TODO.md)
|
- 🛠️ **Firmware** — fw 0.7.1 on `main` (CI + tuner, DSP, BT, presets); see [`Software/docs/TODO.md`](Software/docs/TODO.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
Open-source Hi-Fi DAB+/FM receiver firmware for the ESP32-S3.
|
Open-source Hi-Fi DAB+/FM receiver firmware for the ESP32-S3.
|
||||||
|
|
||||||
**Status:** fw **0.7.0** — companion-chip boot (Si4684, ADAU1701, BT1035),
|
**Status:** fw **0.7.1** — CI on `main` (host tests, Doxygen, manual sync);
|
||||||
Wi-Fi provisioning, tuner/audio REST API, Bluetooth pairing, station presets.
|
companion-chip boot, REST API, Bluetooth pairing, station presets.
|
||||||
See [`docs/TODO.md`](docs/TODO.md) for the agent task list.
|
See [`docs/TODO.md`](docs/TODO.md) for the agent task list.
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
@@ -26,7 +26,7 @@ cmake --build build-host
|
|||||||
ctest --test-dir build-host --output-on-failure
|
ctest --test-dir build-host --output-on-failure
|
||||||
```
|
```
|
||||||
|
|
||||||
Documentation gates (must exit 0 before merging):
|
Documentation gates (must exit 0 before merging; also enforced in CI):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
doxygen Doxyfile
|
doxygen Doxyfile
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ namespace core {
|
|||||||
*
|
*
|
||||||
* @dname AudioEnhancements
|
* @dname AudioEnhancements
|
||||||
* @return n/a (type)
|
* @return n/a (type)
|
||||||
* @pubstate Mapped to PEQ bands at runtime (Chapter~\ref{ch:sigmastudio}).
|
* @pubstate Mapped to PEQ bands at runtime (manual chapter sigmastudio).
|
||||||
* No dedicated SigmaStudio blocks; see \texttt{applyEnhancementsToEq}.
|
* No dedicated SigmaStudio blocks; see \c applyEnhancementsToEq.
|
||||||
*
|
*
|
||||||
* @author Michele Bigi
|
* @author Michele Bigi
|
||||||
* @date 2026-07-06
|
* @date 2026-07-06
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ namespace core {
|
|||||||
* @brief serializeAudioSavedJson — success response after profile apply.
|
* @brief serializeAudioSavedJson — success response after profile apply.
|
||||||
*
|
*
|
||||||
* @dname serializeAudioSavedJson
|
* @dname serializeAudioSavedJson
|
||||||
* @return JSON object \texttt{\{"status":"saved"\}}.
|
* @return JSON object with \c status set to \c saved.
|
||||||
* @pubstate none
|
* @pubstate none
|
||||||
*
|
*
|
||||||
* @author Michele Bigi
|
* @author Michele Bigi
|
||||||
@@ -77,7 +77,7 @@ namespace core {
|
|||||||
[[nodiscard]] std::string serializeAudioErrorJson(std::string_view reason);
|
[[nodiscard]] std::string serializeAudioErrorJson(std::string_view reason);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief parseEnhanceLevelJson — parse POST body \texttt{\{"level":0..100\}}.
|
* @brief parseEnhanceLevelJson — parse POST body with level 0..100.
|
||||||
*
|
*
|
||||||
* @dname parseEnhanceLevelJson
|
* @dname parseEnhanceLevelJson
|
||||||
* @param json Untrusted request body.
|
* @param json Untrusted request body.
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ inline constexpr std::size_t kBt1035BootInitCommandCount = 2U;
|
|||||||
*
|
*
|
||||||
* @dname buildBt1035AtLine
|
* @dname buildBt1035AtLine
|
||||||
* @param command Typed AT command.
|
* @param command Typed AT command.
|
||||||
* @return Full line including \r\n suffix.
|
* @return Full line including CRLF suffix.
|
||||||
* @pubstate none
|
* @pubstate none
|
||||||
*
|
*
|
||||||
* @author Michele Bigi
|
* @author Michele Bigi
|
||||||
|
|||||||
@@ -59,12 +59,67 @@ public:
|
|||||||
std::optional<FrequencyKHz> fmFrequency,
|
std::optional<FrequencyKHz> fmFrequency,
|
||||||
std::optional<PresetSlot> presetSlot);
|
std::optional<PresetSlot> presetSlot);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief name — read the preset display label.
|
||||||
|
*
|
||||||
|
* @dname name
|
||||||
|
* @return Station name value.
|
||||||
|
* @pubstate reads name_.
|
||||||
|
*/
|
||||||
[[nodiscard]] const StationName& name() const noexcept;
|
[[nodiscard]] const StationName& name() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief band — read the target RF band.
|
||||||
|
*
|
||||||
|
* @dname band
|
||||||
|
* @return Dab or Fm band selector.
|
||||||
|
* @pubstate reads band_.
|
||||||
|
*/
|
||||||
[[nodiscard]] TunerBand band() const noexcept;
|
[[nodiscard]] TunerBand band() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief dabFreqIndex — read the Band III ensemble index.
|
||||||
|
*
|
||||||
|
* @dname dabFreqIndex
|
||||||
|
* @return Ensemble index 0–37.
|
||||||
|
* @pubstate reads dabFreqIndex_.
|
||||||
|
*/
|
||||||
[[nodiscard]] std::uint8_t dabFreqIndex() const noexcept;
|
[[nodiscard]] std::uint8_t dabFreqIndex() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief dabServiceId — read optional DAB service id for play().
|
||||||
|
*
|
||||||
|
* @dname dabServiceId
|
||||||
|
* @return Service id when stored, otherwise empty.
|
||||||
|
* @pubstate reads dabServiceId_.
|
||||||
|
*/
|
||||||
[[nodiscard]] std::optional<std::uint32_t> dabServiceId() const noexcept;
|
[[nodiscard]] std::optional<std::uint32_t> dabServiceId() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief dabComponentId — read optional DAB component id for play().
|
||||||
|
*
|
||||||
|
* @dname dabComponentId
|
||||||
|
* @return Component id when stored, otherwise empty.
|
||||||
|
* @pubstate reads dabComponentId_.
|
||||||
|
*/
|
||||||
[[nodiscard]] std::optional<std::uint32_t> dabComponentId() const noexcept;
|
[[nodiscard]] std::optional<std::uint32_t> dabComponentId() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief fmFrequency — read FM centre frequency when band is Fm.
|
||||||
|
*
|
||||||
|
* @dname fmFrequency
|
||||||
|
* @return Frequency when stored, otherwise empty.
|
||||||
|
* @pubstate reads fmFrequency_.
|
||||||
|
*/
|
||||||
[[nodiscard]] std::optional<FrequencyKHz> fmFrequency() const noexcept;
|
[[nodiscard]] std::optional<FrequencyKHz> fmFrequency() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief presetSlot — read optional hardware preset button slot.
|
||||||
|
*
|
||||||
|
* @dname presetSlot
|
||||||
|
* @return Preset slot when assigned, otherwise empty.
|
||||||
|
* @pubstate reads presetSlot_.
|
||||||
|
*/
|
||||||
[[nodiscard]] std::optional<PresetSlot> presetSlot() const noexcept;
|
[[nodiscard]] std::optional<PresetSlot> presetSlot() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ public:
|
|||||||
* @pubstate sets booted_ after Ping + AT+AUXCFG=1 both return OK.
|
* @pubstate sets booted_ after Ping + AT+AUXCFG=1 both return OK.
|
||||||
*
|
*
|
||||||
* Sequence: hardware reset, UART @ 115200 with RTS/CTS, then
|
* Sequence: hardware reset, UART @ 115200 with RTS/CTS, then
|
||||||
* core::bootInitSequence() (Chapter~\ref{ch:bt1035}).
|
* core::bootInitSequence() (see manual chapter bt1035).
|
||||||
*
|
*
|
||||||
* @author Michele Bigi
|
* @author Michele Bigi
|
||||||
* @date 2026-07-06
|
* @date 2026-07-06
|
||||||
|
|||||||
@@ -66,6 +66,9 @@ public:
|
|||||||
* @param store Secure store consulted for saved STA credentials.
|
* @param store Secure store consulted for saved STA credentials.
|
||||||
* @param tuner Tuner service exposed by the HTTP API.
|
* @param tuner Tuner service exposed by the HTTP API.
|
||||||
* @param audio Audio service exposed by the HTTP API.
|
* @param audio Audio service exposed by the HTTP API.
|
||||||
|
* @param bluetooth Bluetooth pairing service for REST routes.
|
||||||
|
* @param stations Station preset service for REST routes.
|
||||||
|
* @param companionChips Boot flags exposed on GET /api/health.
|
||||||
* @return NetBootstrap on success, or a NetError.
|
* @return NetBootstrap on success, or a NetError.
|
||||||
* @pubstate none
|
* @pubstate none
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ public:
|
|||||||
* @param audio Audio service for the audio REST routes.
|
* @param audio Audio service for the audio REST routes.
|
||||||
* @param bluetooth Bluetooth service for pairing REST routes.
|
* @param bluetooth Bluetooth service for pairing REST routes.
|
||||||
* @param stations Station preset service for list REST routes.
|
* @param stations Station preset service for list REST routes.
|
||||||
|
* @param companionChips Boot flags for GET /api/health.
|
||||||
* @return Ok on success, or NetError::HttpServerStartFailed.
|
* @return Ok on success, or NetError::HttpServerStartFailed.
|
||||||
* @pubstate writes server_, store_, netState_, and service pointers on success.
|
* @pubstate writes server_, store_, netState_, and service pointers on success.
|
||||||
*
|
*
|
||||||
|
|||||||
+9
-24
@@ -12,9 +12,8 @@ errors, no plaintext secrets.
|
|||||||
|
|
||||||
Working directory for all commands is `Software/`.
|
Working directory for all commands is `Software/`.
|
||||||
|
|
||||||
**Current firmware:** `0.7.0` — BT1035 pairing (`/api/bluetooth/*`),
|
**Current firmware:** `0.7.1` — CI green gate (Doxygen + host tests +
|
||||||
station presets (`/api/stations/*`), host tests green (10/10), manual
|
manual sync), BT1035 pairing, station presets.
|
||||||
sync green (38 classes).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -30,28 +29,14 @@ sync green (38 classes).
|
|||||||
|
|
||||||
## P0 — Fix the build gate (do this first)
|
## P0 — Fix the build gate (do this first)
|
||||||
|
|
||||||
### T1. Clear the 16 Doxygen warnings
|
### T1. Clear the 16 Doxygen warnings — **DONE (fw 0.7.1)**
|
||||||
**Why:** `doxygen Doxyfile` currently exits non-zero, so the docs gate is
|
Fixed invalid `\texttt`/`\r`/`\ref` in doc blocks; documented
|
||||||
red and CI (once added) will fail.
|
`Station` accessors and `NetBootstrap`/`SetupWebServer` parameters.
|
||||||
**What:**
|
`doxygen Doxyfile` exits 0 with an empty warnings log.
|
||||||
- Replace the invalid `\texttt{...}` with `` `...` `` (backticks) or
|
|
||||||
`\c word` in: `core/AudioProfileJson.hpp` (l.58, l.80),
|
|
||||||
`core/AudioEnhancements.hpp` (l.25).
|
|
||||||
- Fix `\r` interpreted as a command in `core/Bt1035At.hpp` (l.64) —
|
|
||||||
wrap the AT string in `@code ... @endcode` or escape as `\\r`.
|
|
||||||
- Add a space after `\ref` in `bt1035/Bt1035Driver.hpp` (l.89) and
|
|
||||||
`core/AudioEnhancements.hpp` (l.24).
|
|
||||||
- Document the missing `@param companionChips` in
|
|
||||||
`net/NetBootstrap.hpp` (`start`) and `net/SetupWebServer.hpp` (`start`).
|
|
||||||
**Done when:** `doxygen Doxyfile` exits 0 and `docs/api/doxygen-warnings.log`
|
|
||||||
is empty.
|
|
||||||
|
|
||||||
### T2. Add the CI workflow
|
### T2. Add the CI workflow — **DONE (fw 0.7.1)**
|
||||||
**Why:** validate every push automatically.
|
`.github/workflows/ci.yml`: host `ctest`, Doxygen, manual sync on every
|
||||||
**What:** add `.github/workflows/ci.yml` with three jobs — host build +
|
push/PR to `main`.
|
||||||
`ctest`, `doxygen` (fail on warnings), and `check-manual-sync.py`. A ready
|
|
||||||
draft was prepared; place it and confirm all three jobs pass.
|
|
||||||
**Done when:** the workflow is green on `main` after T1.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,20 @@ doxygen Doxyfile
|
|||||||
python3 tools/check-manual-sync.py
|
python3 tools/check-manual-sync.py
|
||||||
\end{drcode}
|
\end{drcode}
|
||||||
|
|
||||||
|
\section{Continuous integration}
|
||||||
|
|
||||||
|
Every push and pull request to \texttt{main} runs
|
||||||
|
\texttt{.github/workflows/ci.yml} at the repository root (three parallel
|
||||||
|
jobs, all from the \texttt{Software/} directory):
|
||||||
|
|
||||||
|
\begin{enumerate}
|
||||||
|
\item \textbf{Host tests} --- \texttt{cmake} + \texttt{ctest} on
|
||||||
|
\texttt{components/core/test} (C++23, \texttt{g++-14} on Ubuntu).
|
||||||
|
\item \textbf{Doxygen} --- must exit 0 with an empty
|
||||||
|
\texttt{docs/api/doxygen-warnings.log}.
|
||||||
|
\item \textbf{Manual sync} --- \texttt{tools/check-manual-sync.py}.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
To rebuild the PDF manual (requires a LaTeX installation):
|
To rebuild the PDF manual (requires a LaTeX installation):
|
||||||
|
|
||||||
\begin{drcode}[Manual PDF]
|
\begin{drcode}[Manual PDF]
|
||||||
|
|||||||
Reference in New Issue
Block a user