docs: spec enigmes locales Freenove P1/P3
Repo State / repo-state (push) Failing after 1m7s

This commit is contained in:
Claude Worker claude2
2026-06-10 13:34:39 +02:00
parent 19bce1075a
commit 7ee051827f
@@ -0,0 +1,174 @@
# Freenove Media Kit — énigmes locales (P1 son, P3 QR) — Design Spec
> Statut : design validé en brainstorming (2026-06-10), à relire avant plan
> d'implémentation. Approche retenue : **A — composant `local_puzzles`**.
## Contexte & objectif
La Freenove **ESP32-S3 Media Kit v1.2** (module **N16R8** : 16 Mo flash,
8 Mo PSRAM octale, caméra **OV2640**, micro I2S MEMS, haut-parleur, SD,
batterie) exécute le firmware master `idf_zacus`. Aujourd'hui le master est un
orchestrateur headless (ESP-NOW hub, `game_endpoint`, `voice_pipeline`,
`npc_engine`, relay scénario), et les énigmes sont des **nœuds ESP32 dédiés**
(`puzzles/p1,p5,p6,p7`).
**Objectif** : faire de la Freenove un **master portable tout-en-un** qui, en
plus d'orchestrer, prend en charge **directement** deux énigmes via ses
capteurs intégrés :
- **P3 — QR Treasure** : scanner N QR codes dans le bon ordre (caméra OV2640).
- **P1 — Séquence sonore** : valider une mélodie reproduite par le joueur
(micro I2S).
Les énigmes **P5 morse / P6 NFC / P7 coffre**, ainsi que **BOX-3** et **PLIP**,
restent des nœuds ESP-NOW : aucune modification de leur firmware.
### Non-objectifs
- Pas de migration de P5/P6/P7 sur la Freenove (périphériques externes non
« média » ; hors scope de ce spec).
- Pas de suppression du protocole ESP-NOW ni du `game_endpoint` existant.
- Pas de refonte du `npc_engine` / `voice_pipeline` au-delà du strict
nécessaire pour partager le micro.
## Architecture — `idf_zacus/components/local_puzzles/`
Nouveau composant, trois unités à responsabilité unique + un point d'entrée
commun. Chaque unité est testable et remplaçable indépendamment.
### `mic_broker`
Possède le canal I2S micro (RX) et distribue les frames PCM16 16 kHz à **un
seul** consommateur actif, selon un mode explicite :
```
typedef enum { MIC_IDLE, MIC_NPC_LISTEN, MIC_P1_SOUND } mic_mode_t;
void mic_broker_set_mode(mic_mode_t mode);
// Un consommateur s'enregistre ; il ne reçoit des frames que dans son mode.
void mic_broker_register(mic_mode_t mode, mic_frame_cb_t cb, void *ctx);
```
- Résout la **contention micro** par construction : NPC et P1 ne tournent
jamais en même temps.
- `voice_pipeline` est refactoré pour **tirer ses frames du broker**
(`MIC_NPC_LISTEN`) au lieu de posséder l'I2S directement. Changement minimal :
le broker encapsule l'init I2S existante du `voice_pipeline`.
- Le mode est piloté par l'état de scénario (voir Flux de données).
### `qr_puzzle`
- Init **`esp32-camera`** (composant `espressif/esp32-camera`) avec le pin-map
**Freenove ESP32-S3 Media Kit** (OV2640, voir Annexe pin-map).
- Décodage QR via **`quirc`** (bibliothèque C, intégrée en composant — **pas**
la lib Arduino `lib/ESP32QRCodeReader_vendor`, incompatible IDF).
- Boucle de scan active **uniquement** quand P3 est en cours ; accumule les
codes lus et valide la **séquence** contre l'ordre attendu (réutilise la
logique `correct_order` du bloc P3 de l'atelier).
- Caméra **dé-initialisée** hors P3 (`esp_camera_deinit`) — économie batterie
et libération PSRAM.
### `sound_puzzle`
- Consommateur `MIC_P1_SOUND` du broker.
- Détection d'attaque/hauteur (énergie + estimation de fréquence, fenêtres
glissantes) ; valide la **séquence de notes** reproduite contre la mélodie
attendue (logique reprise du nœud `puzzles/p1_sequence_sonore`).
- Tolérance/seuils paramétrables (difficulté).
### `local_puzzle_report()`
```
void local_puzzle_report(uint8_t puzzle_id, const uint8_t code_fragment[4]);
```
Point d'entrée commun : **synthétise un événement « puzzle résolu »** dans
`game_endpoint`, identique au chemin du handler `MSG_PUZZLE_SOLVED` des nœuds
ESP-NOW. Le master traite ainsi énigmes **locales et distantes de façon
uniforme** (assemblage du code, ligne NPC, LED, scoring).
## Flux de données
```
scénario/état de jeu
│ active P1 ou P3 (étape courante)
local_puzzles ──arme le module──► qr_puzzle / sound_puzzle
│ règle le mode micro (mic_broker_set_mode)
succès (séquence/mélodie correcte)
local_puzzle_report(puzzle_id, code_fragment)
game_endpoint ──► même aval que les énigmes ESP-NOW
(code assemblé, NPC, LED, score)
```
## Configuration & compatibilité
Chaque énigme est déclarée **`local` vs `remote`** (dans `boards.yaml` master
ou le scénario). Le **même firmware** fonctionne que P1/P3 soient locaux
(Freenove) ou en nœud ESP-NOW. Le nœud `puzzles/p1_sequence_sonore` devient
**optionnel** : repli si la caméra/micro local est indisponible.
## Gestion des erreurs & batterie
- **Échec init caméra** → P3 retombe sur le nœud ESP-NOW s'il est déclaré,
sinon log d'erreur et P3 inactif (le reste du jeu continue).
- **Contention micro** → impossible (mode exclusif du broker).
- **Batterie** → caméra dé-initialisée hors P3 ; micro en `MIC_IDLE` quand ni
NPC ni P1 actifs. Pas de capture inutile.
- **PSRAM** → 8 Mo octale (N16R8) : framebuffer caméra (QVGA/VGA suffisant pour
QR) + quirc large ; budget confortable.
## Tests
- **Logique pure (host)** : validateur de séquence QR (`correct_order`) et
validateur de mélodie (séquence de notes + tolérance) — tests unitaires sans
matériel.
- **Smoke hardware** : scanner un QR connu → `qr_puzzle` rapporte la bonne
valeur ; jouer un ton/mélodie → `sound_puzzle` valide ; vérifier que
`local_puzzle_report` déclenche le même aval qu'un `MSG_PUZZLE_SOLVED` ESP-NOW.
- **Régression** : NPC vocal toujours fonctionnel (le broker n'a pas cassé le
`voice_pipeline`).
## Découpage suggéré (pour le plan)
1. `mic_broker` + refacto `voice_pipeline` pour passer par le broker (NPC
inchangé fonctionnellement). **Indépendant, testable seul.**
2. `qr_puzzle` (caméra + quirc + validateur de séquence) + `local_puzzle_report`
branché sur `game_endpoint`. **Livrable visible : P3 sur la Freenove.**
3. `sound_puzzle` (détection mélodie via broker). **Livrable : P1 sur la
Freenove.**
4. Flag de config `local|remote` par énigme + repli ESP-NOW.
Chaque étape compile et est flashable indépendamment.
## Annexe — pin-map caméra Freenove ESP32-S3 (OV2640)
À confirmer sur le schéma **Media Kit v1.2** avant implémentation (valeurs
Freenove ESP32-S3-WROOM CAM standard) :
| Signal | GPIO | Signal | GPIO |
|---|---|---|---|
| PWDN | -1 | HREF | 7 |
| RESET | -1 | PCLK | 13 |
| XCLK | 15 | D7 | 16 |
| SIOD (SDA) | 4 | D6 | 17 |
| SIOC (SCL) | 5 | D5 | 18 |
| VSYNC | 6 | D4 | 12 |
| D3 | 10 | D2 | 8 |
| D1 | 9 | D0 | 11 |
**Micro I2S MEMS** : pins à confirmer sur le schéma Media Kit v1.2 (le
`voice_pipeline` actuel connaît déjà la config micro du master — la réutiliser
via le broker plutôt que la redéfinir).
## Inconnues résiduelles (à lever au début du plan)
1. Pins exactes du **micro I2S** sur le Media Kit v1.2 (récupérer depuis la
config `voice_pipeline` existante).
2. Confirmer **OV2640** (vs OV5640) et la résolution minimale fiable pour le
décodage QR à la distance de jeu.
3. Disponibilité du composant **`quirc`** en registre IDF, sinon vendoring.