Document Si4684 blob procurement and enforce CI policy.
Expand local-only firmware README, add check_si4684_blobs.py to verify gitignore and clean history, and gate main with a new si4684-blobs workflow job. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9,10 +9,16 @@ Binary and SigmaStudio exports loaded by the ESP32 at every boot.
|
||||
|
||||
## Si4684 blobs
|
||||
|
||||
`rom_patch_016.bin` and `dab_firmware.bin` are extracted from the
|
||||
[PE5PVB SI4684-DAB-Receiver](https://github.com/PE5PVB/SI4684-DAB-Receiver)
|
||||
project. `fm_firmware.bin` comes from the Skyworks Si4684 eval firmware pack
|
||||
(see `tools/fetch_si4684_firmware.py --si46xx-dir`).
|
||||
Proprietary Skyworks images — **local only**, gitignored (`*.bin`). See
|
||||
[`Si4684-Firmware/README.md`](Si4684-Firmware/README.md) for procurement and
|
||||
legal notes. Populate with:
|
||||
|
||||
```bash
|
||||
cd Software
|
||||
python3 tools/fetch_si4684_firmware.py --dab-only
|
||||
python3 tools/fetch_si4684_firmware.py --si46xx-dir /path/to/si46xx_firmware
|
||||
python3 tools/check_si4684_blobs.py
|
||||
```
|
||||
|
||||
## ADAU1701 export
|
||||
|
||||
|
||||
@@ -1,43 +1,89 @@
|
||||
# Si4684 firmware images
|
||||
# Si4684 firmware images (local only — not in git)
|
||||
|
||||
Skyworks Si4684 application firmware is **proprietary**. This directory holds
|
||||
the three binary blobs your build embeds via `HOST_LOAD`; they must **never**
|
||||
be committed to the public repository.
|
||||
|
||||
| File | Size (typ.) | Role |
|
||||
|------|-------------|------|
|
||||
| `rom_patch_016.bin` | 5796 | ROM patch / bootloader helper (HOST_LOAD before main image) |
|
||||
| `rom_patch_016.bin` | 5796 B | ROM patch / bootloader helper (HOST_LOAD before main image) |
|
||||
| `dab_firmware.bin` | ~517 KB | DAB+ application image (PE5PVB / Skyworks BIF) |
|
||||
| `fm_firmware.bin` | ~530 KB | FM application image (Skyworks `fm_radio_5_1_0.bin`, AN649 A10) |
|
||||
|
||||
Boot sequence: AN649 — POWER_UP → LOAD_INIT → HOST_LOAD(patch) → LOAD_INIT →
|
||||
HOST_LOAD(image) → BOOT. DAB and FM use the same patch; only the application
|
||||
Boot sequence (AN649): POWER_UP → LOAD_INIT → HOST_LOAD(patch) → LOAD_INIT →
|
||||
HOST_LOAD(image) → BOOT. DAB and FM share the same patch; only the application
|
||||
image differs.
|
||||
|
||||
## Refresh blobs
|
||||
## Legal / redistribution
|
||||
|
||||
- **Do not** commit `*.bin` files here, attach them to GitHub releases, or
|
||||
redistribute them with this open-source tree.
|
||||
- DAB images extracted from [PE5PVB/SI4684-DAB-Receiver](https://github.com/PE5PVB/SI4684-DAB-Receiver) are community-sourced; FM images come from the
|
||||
Skyworks evaluation package or equivalent local sources (see below).
|
||||
- Keep blobs on your machine only. CI verifies they are gitignored and absent
|
||||
from history (`python3 tools/check_si4684_blobs.py`).
|
||||
|
||||
## Before you build
|
||||
|
||||
From `Software/`:
|
||||
|
||||
```bash
|
||||
# DAB + patch from PE5PVB GitHub (always safe to re-run):
|
||||
python3 tools/fetch_si4684_firmware.py --dab-only
|
||||
|
||||
# FM from Skyworks eval / dabpi si46xx_firmware folder:
|
||||
python3 tools/fetch_si4684_firmware.py --si46xx-dir /path/to/si46xx_firmware
|
||||
|
||||
# FM extracted from uGreen DABBoard radio_cli (Files_v16.zip from ugreen.eu/downloads):
|
||||
python3 tools/fetch_si4684_firmware.py --from-ugreen-radio-cli ~/Downloads/Files_v16.zip
|
||||
|
||||
# Patch + DAB + FM entirely from uGreen radio_cli (overrides PE5PVB DAB):
|
||||
python3 tools/fetch_si4684_firmware.py --from-ugreen-radio-cli ~/Downloads/Files_v16.zip --ugreen-all
|
||||
|
||||
# FM extracted from a full SPI flash dump (TechniSat layout, dirb.me tech wiki):
|
||||
python3 tools/fetch_si4684_firmware.py --flash-dump technisat_spi.bin
|
||||
python3 tools/fetch_si4684_firmware.py --dab-only # patch + DAB
|
||||
python3 tools/fetch_si4684_firmware.py --si46xx-dir /path # add FM (see below)
|
||||
ls -la Firmware/Si4684-Firmware/*.bin # expect 3 files
|
||||
```
|
||||
|
||||
FM images are **not** redistributed with PE5PVB (DAB-only project). Obtain
|
||||
`fm_radio_5_1_0.bin` from the Si4684 evaluation package (AN649 table 1),
|
||||
community `si46xx_firmware/` folders used by [teknoid/dabpi](https://github.com/teknoid/dabpi),
|
||||
or extract from a uGreen [DABBoard](https://ugreen.eu/downloads/) `radio_cli`
|
||||
binary (proprietary — keep local, do not commit to public git).
|
||||
`idf.py build` fails at link/embed time if blobs are missing.
|
||||
|
||||
Low-level conversion helper:
|
||||
## Obtain images locally
|
||||
|
||||
### Patch + DAB (automated, network)
|
||||
|
||||
```bash
|
||||
python3 tools/extract_si4684_blob.py --copy /path/to/fm_radio_5_1_0.bin \\
|
||||
cd Software
|
||||
python3 tools/fetch_si4684_firmware.py --dab-only
|
||||
```
|
||||
|
||||
Clones PE5PVB/SI4684-DAB-Receiver and writes `rom_patch_016.bin` and
|
||||
`dab_firmware.bin`.
|
||||
|
||||
### FM image (manual source — pick one)
|
||||
|
||||
FM is **not** shipped with PE5PVB. Supply one of:
|
||||
|
||||
| Source | Command |
|
||||
|--------|---------|
|
||||
| Skyworks eval / dabpi `si46xx_firmware/` | `python3 tools/fetch_si4684_firmware.py --si46xx-dir /path/to/si46xx_firmware` |
|
||||
| uGreen DABBoard `Files_v16.zip` | `python3 tools/fetch_si4684_firmware.py --from-ugreen-radio-cli ~/Downloads/Files_v16.zip` |
|
||||
| Full SPI flash dump (TechniSat layout) | `python3 tools/fetch_si4684_firmware.py --flash-dump technisat_spi.bin` |
|
||||
|
||||
Candidate FM filenames (AN649 / community): `fm_radio_5_1_0.bin`,
|
||||
`fm_radio_5_0_9.bin`, `fmhd_radio_5_1_0.bin`, `fmhd_radio_5_0_4.bin`.
|
||||
|
||||
Manual copy helper:
|
||||
|
||||
```bash
|
||||
python3 tools/extract_si4684_blob.py --copy /path/to/fm_radio_5_1_0.bin \
|
||||
--out Firmware/Si4684-Firmware/fm_firmware.bin
|
||||
```
|
||||
|
||||
### All three from uGreen radio_cli
|
||||
|
||||
```bash
|
||||
python3 tools/fetch_si4684_firmware.py --from-ugreen-radio-cli ~/Downloads/Files_v16.zip --ugreen-all
|
||||
```
|
||||
|
||||
## Verify your checkout
|
||||
|
||||
```bash
|
||||
cd Software
|
||||
python3 tools/check_si4684_blobs.py # must exit 0
|
||||
git ls-files 'Firmware/Si4684-Firmware/*.bin' # must print nothing
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- Skyworks **AN649** — Si4684 programming API and boot flow
|
||||
- `tools/fetch_si4684_firmware.py` — fetch/extract orchestration
|
||||
- `tools/extract_si4684_blob.py` — header/array → raw `.bin`
|
||||
- `docs/manual/ch-si4684.tex` — driver boot integration in DigiRadio
|
||||
|
||||
@@ -31,6 +31,7 @@ Documentation gates (must exit 0 before merging; also enforced in CI):
|
||||
```bash
|
||||
doxygen Doxyfile
|
||||
python3 tools/check-manual-sync.py
|
||||
python3 tools/check_si4684_blobs.py
|
||||
python3 tools/gzip-www.sh # after editing components/net/www/index.html
|
||||
```
|
||||
|
||||
|
||||
+4
-12
@@ -69,18 +69,10 @@ embedded gzip blob. No debug routes in `SetupWebServer`.
|
||||
|
||||
## P3 — Procurement & hardening
|
||||
|
||||
### T7. Si4684 firmware blob strategy (legal)
|
||||
**Why:** the Si4684 images are proprietary (Skyworks). Tools to fetch/
|
||||
extract exist under `tools/`, but the `.bin` images must **not** be
|
||||
committed to the public repo.
|
||||
**What:**
|
||||
- Confirm `*.bin` (patch, FM, DAB images) are in `.gitignore` and absent
|
||||
from git history.
|
||||
- Document in `Software/Firmware/Si4684-Firmware/README.md` how a builder
|
||||
obtains the images locally (tools + AN649 reference), without
|
||||
redistributing proprietary binaries.
|
||||
**Done when:** no proprietary blob is tracked; the procurement path is
|
||||
documented and reproducible.
|
||||
### T7. Si4684 firmware blob strategy (legal) — **DONE (fw 0.8.2)**
|
||||
`Firmware/Si4684-Firmware/*.bin` gitignored; no blobs in git history.
|
||||
Procurement documented in `Si4684-Firmware/README.md`; CI job
|
||||
`si4684-blobs` runs `tools/check_si4684_blobs.py`.
|
||||
|
||||
### T8. Flash/NVS encryption enablement
|
||||
**Why:** secure storage holds Wi-Fi and user credentials; encryption at
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python3
|
||||
"""check_si4684_blobs.py — CI gate: no proprietary Si4684 blobs in git.
|
||||
|
||||
DigiRadio firmware — https://github.com/manvalan/DigiRadio
|
||||
|
||||
Copyright 2026 Michele Bigi
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
Skyworks / uGreen Si4684 application images must live only on the builder's
|
||||
machine under Firmware/Si4684-Firmware/*.bin (gitignored). This script fails
|
||||
if any such blob is tracked, appears in git history, or is missing from
|
||||
.gitignore.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
FW_DIR = ROOT / "Firmware" / "Si4684-Firmware"
|
||||
GITIGNORE = ROOT / ".gitignore"
|
||||
IGNORE_LINE = "Firmware/Si4684-Firmware/*.bin"
|
||||
|
||||
|
||||
def git(*args: str) -> str:
|
||||
result = subprocess.run(
|
||||
["git", *args],
|
||||
cwd=ROOT.parent,
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
return result.stdout
|
||||
|
||||
|
||||
def check_gitignore() -> list[str]:
|
||||
errors: list[str] = []
|
||||
if not GITIGNORE.is_file():
|
||||
errors.append(f"missing {GITIGNORE.relative_to(ROOT)}")
|
||||
return errors
|
||||
text = GITIGNORE.read_text(encoding="utf-8")
|
||||
if IGNORE_LINE not in text:
|
||||
errors.append(
|
||||
f".gitignore must contain {IGNORE_LINE!r} "
|
||||
"(proprietary Si4684 blobs)"
|
||||
)
|
||||
return errors
|
||||
|
||||
|
||||
def check_tracked_bins() -> list[str]:
|
||||
out = git("ls-files", "--", "Software/Firmware/Si4684-Firmware/*.bin")
|
||||
tracked = [line for line in out.splitlines() if line.strip()]
|
||||
if not tracked:
|
||||
return []
|
||||
return [
|
||||
"tracked Si4684 blob(s) in git index (remove and keep local only): "
|
||||
+ ", ".join(tracked)
|
||||
]
|
||||
|
||||
|
||||
def check_history() -> list[str]:
|
||||
out = git(
|
||||
"log",
|
||||
"--all",
|
||||
"--oneline",
|
||||
"--",
|
||||
"Software/Firmware/Si4684-Firmware/*.bin",
|
||||
)
|
||||
lines = [line for line in out.splitlines() if line.strip()]
|
||||
if not lines:
|
||||
return []
|
||||
return [
|
||||
"Si4684 .bin file(s) found in git history — "
|
||||
"history rewrite required before publishing: "
|
||||
+ "; ".join(lines[:5])
|
||||
+ (" …" if len(lines) > 5 else "")
|
||||
]
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Ensure Si4684 firmware blobs are not in git."
|
||||
)
|
||||
parser.parse_args()
|
||||
errors = check_gitignore() + check_tracked_bins() + check_history()
|
||||
if errors:
|
||||
for err in errors:
|
||||
print(f"check_si4684_blobs: error: {err}", file=sys.stderr)
|
||||
return 1
|
||||
print(
|
||||
"Si4684 blob policy OK: "
|
||||
f"{IGNORE_LINE} gitignored, no tracked blobs, clean history."
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user