# Telemetry Bridge — firmware unico multi-modo ESP32 DevKit che riceve la telemetria CRSF dal **TX Backpack ELRS** via ESP-NOW e la espone in **4 modalità selezionabili a runtime** (comando seriale, scelta salvata in NVS). Un solo firmware da compilare; nessuna ricompilazione per cambiare uso. ## Modalità | # | Nome | USB | Cosa fa | |---|-----------|------------|------------------------------------------------------------------| | 0 | HUMAN | testo | Dashboard leggibile (GPS, batteria, assetto, link) a 1 Hz | | 1 | CRSF_DUMP | testo | Dump esadecimale grezzo di ogni frame CRSF (debug/reverse) | | 2 | LTM | binario | Traduce CRSF → **LTM v2** per **mwptools** (monitoraggio volo) | | 3 | MAVLINK | binario | Traduce CRSF → **MAVLink v2** per mwptools (include corrente in A)| ## Selezione della modalità (comando seriale) La scelta è persistente (NVS). Dal **monitor seriale @115200** digita: - `!` seguito da `0`..`3` → seleziona quel modo direttamente; - `!` seguito da `m` → passa al modo successivo (ciclico). La board salva la scelta in NVS e si riavvia nel nuovo modo. Senza comando, riparte sull'ultimo modo salvato. > **Perché un comando seriale e non il pulsante BOOT.** BOOT è GPIO0, *strapping > pin* del bootloader: tenerlo premuto al reset manda l'ESP32 in download mode > invece di eseguire il firmware, quindi il cambio modo via BOOT non era > affidabile. Il prefisso `!` è obbligatorio perché mwp in modo INAV interroga via > MSP (byte `$M<...`): senza prefisso la `M` verrebbe interpretata come comando e > farebbe cambiare modo da sola. ## Uso con mwptools Entrambi i modi LTM e MAVLink sono **downlink unidirezionale** — perfetti per il path downlink-only del backpack. In mwp: *Connect* → **porta USB** dell'ESP32 → protocollo **INAV**, baud **115200**. - **Modo LTM (#2):** posizione, assetto, batteria (V, mAh). LTM in INAV è opera di Jonathan Hudson, lo stesso autore di mwp. - **Modo MAVLINK (#3):** come LTM **più la corrente istantanea in Ampere** (`SYS_STATUS`/`BATTERY_STATUS`), RSSI (`RADIO_STATUS`) e % batteria — campi che LTM non trasporta. Messaggi emessi: HEARTBEAT, SYS_STATUS, GPS_RAW_INT, ATTITUDE, VFR_HUD, BATTERY_STATUS, RADIO_STATUS. > **Problema noto (aperto):** mwp mostra la corrente come ~0.12 A invece di 1.2 A > (fattore ÷10). La codifica del firmware è spec-corretta (`current_battery` in cA: > 120 cA = 1.2 A, verificato a byte). Sembra un'interpretazione non standard lato > mwp; da indagare. > Cosa **non** fa: missioni, lettura/scrittura parametri, qualunque cosa MSP > request/response (bidirezionale). Vedi i limiti qui sotto. ## Limiti uplink (importante, verificato) Il backpack ELRS via ESP-NOW è **downlink-only by design**. I maintainer ELRS (discussion #3510, gen 2026) confermano che il backpack **non** inietta pacchetti arbitrari nell'uplink OTA, e che l'uplink verso l'FC è possibile **solo** dal flusso CRSF dell'handset (radio → TX → OTA → RX → FC), con telemetria attiva. Conseguenza: **MSP bidirezionale verso l'FC attraverso il backpack non è realizzabile** con ELRS stock (per questo il vecchio modo MSP sperimentale è stato rimosso). Per vero MSP bidirezionale con mwp serve un link seriale trasparente dedicato (coppia SiK/3DR 433-915 MHz, oppure mLRS con MSPX): architettura separata, non questo ESP32 sul backpack. ## Struttura del codice ``` platformio.ini src/ main.cpp # dispatcher: comando seriale '!' + NVS, loop sui modi my_config.h # UID (bind phrase), in .gitignore <-- DA COMPILARE my_config.h.example # modello da copiare in my_config.h modes.h # interfaccia Mode {begin,onFrame,tick} mode_human.cpp # modo 0 mode_crsfdump.cpp # modo 1 mode_ltm.cpp # modo 2 (usa lib/Ltm) mode_mavlink.cpp # modo 3 (usa lib/mavlink) lib/ EspNowCrsf/ # init ESP-NOW + ring buffer dei frame CRSF (condiviso) Ltm/ # encoder LTM v2 (layout fedele a inav/ltm.c) terseCRSF/ # parser CRSF VENDORIZZATO e patchato (vedi sotto) mavlink/ # libreria MAVLink ufficiale (c_library_v2, vendorizzata) ``` Aggiungere un nuovo modo = nuovo `mode_xxx.cpp` che esporta un `Mode`, più una riga nell'array `MODES[]` in `main.cpp`. ### Librerie vendorizzate `terseCRSF` e `mavlink` sono copiate in `lib/` (non più via `lib_deps`) così le patch locali sono permanenti e versionate: - **terseCRSF** — patch documentate in cima a `lib/terseCRSF/src/terseCRSF.h`: (1) disattivati i `#define SHOW_*` di debug, che stampavano testo dentro lo stream binario LTM/MAVLink corrompendolo; (2) corretto `bat_fuel_drawn` (leggeva 4 byte includendo il byte percent → mAh consumati errati). - **mavlink** — dialetti `minimal`+`common`+`standard` di `c_library_v2`; include base `-I lib/mavlink` in `platformio.ini` (si include come ``). ## Build / upload Apri la cartella in VSCode/PlatformIO, **Build → Upload → Monitor** (115200). Le librerie sono già in `lib/` (la prima build scarica solo il core 2.0.17). Copia `src/my_config.h.example` in `src/my_config.h` e mettici il tuo **UID** (il file reale è in `.gitignore` perché contiene un dato derivato dalla bind phrase). > Upload: questa board entra in download mode solo tenendo **BOOT premuto** durante > il `Connecting...` di esptool (poi rilascia). Non tenerlo premuto fino al reset > finale.