mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-13 15:11:20 +10:00
* feat: isolate event radio profiles * fix: preserve identity on degraded config boot * fix: guard event profile storage * style: align event profile storage names * fix: discard event profile on normal boot * refactor: simplify event profile cleanup * fix: limit inactive profile migration to event firmware * fix(event): make event-profile capacity check portable across filesystems The USERPREFS_EVENT_MODE storage preflight called FSCom.totalBytes() and FSCom.usedBytes(), which only exist on ESP32's LittleFS wrapper. Every other backend failed to compile once event mode was enabled: error: 'class InternalFileSystem' has no member named 'totalBytes' (nRF52) error: no member named 'totalBytes' in 'fs::FS' (Portduino) This was not caught earlier because the event block is behind #if USERPREFS_EVENT_MODE, and the existing unit tests only cover the pure helpers, which compile identically either way. Add fsTotalBytes()/fsUsedBytes() to FSCommon and implement them per backend: littlefs v1 traversal for nRF52 (Adafruit_LittleFS) and STM32 (STM32_LittleFS), FSInfo for RP2040, statvfs for Portduino, and the native methods for ESP32 and nRF54L15. The nRF52/STM32 path reports "full" if the traversal errors so the capacity check fails safe. Verified with USERPREFS_EVENT_MODE=1: native-macos test_event_profile_storage passes 5/5, and heltec-v3, rak4631, rak11310 and rak3172 all build clean. * fix(event): use std::filesystem for Portduino capacity, bump native-suite-count Two CI fixes: - native-windows has no <sys/statvfs.h>, so the Portduino branch of fsTotalBytes()/fsUsedBytes() broke the Windows build. Switch to std::filesystem::space(), which is already used under ARCH_PORTDUINO in HostMetrics.cpp and works on both POSIX and MinGW. Errors report "full" so the capacity check still fails safe. - This PR adds test/test_event_profile_storage, taking test/ from 40 to 41 suite directories, which trips the native-suite-count reconciliation check. * fix(event): scope boot-write deferral to the radio profile, address review Review feedback: - Copilot: saveProto()'s boot-write deferral applied to every file, so loadFromDisk()'s recovery writes (e.g. restoring owner fields into devicestate) were silently dropped and never retried, because the ctor CRC baselines are computed after loadFromDisk(). Deferral now applies only to the radio-profile files, via isRadioProfileFile(). - jp-bennett: eventConfigFromStandard() wrapped a struct copy plus one field assignment in a header helper with its own unit test. Inlined at its single call site and removed; the behaviour is covered end-to-end by hardware validation instead (RAK4631 normal -> event -> normal preserves NodeNum and public key while swapping LoRa, and restores the original channel byte-identically). - jp-bennett: the active-backup encrypted-storage migration ran for normal builds too, which changed non-event behaviour and contradicted the PR's stated event-only scope. Scoped to USERPREFS_EVENT_MODE; the adjacent block already covers the inactive standard backup in event builds. New tests (all verified to fail under mutation, not vacuous): - test_event_paths_never_collide_with_standard_or_shared_files: the core safety property. A path-table slip would make event firmware overwrite the user's real config, channels or backup, or capture a shared file like devicestate/nodedb. Nothing asserted this before. - test_only_radio_profile_files_defer_boot_writes: guards the deferral fix above so re-widening it fails loudly. - test_event_reservation_fits_smallest_supported_filesystem: the reservation is compile-time but must fit filesystems as small as 14 KiB (STM32WL) and 28 KiB (nRF52840). Protobuf growth pushing it past those would silently stop event profiles persisting - the exact failure mode confirmed by fault injection on a RAK4631. Verified with USERPREFS_EVENT_MODE both on and off: 7/7 tests pass, and rak4631, heltec-v3, rak11310 and rak3172 all build clean. * fix: preserve event profile storage recovery --------- Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz> Co-authored-by: Ben Meadors <benmmeadors@gmail.com> Co-authored-by: Benjamin Faershtein <benjaminfaershtein@Benjamins-MacBook-Pro-2.local>
77 lines
2.1 KiB
C++
77 lines
2.1 KiB
C++
#pragma once
|
|
|
|
#include "configuration.h"
|
|
#include <vector>
|
|
|
|
// Cross platform filesystem API
|
|
|
|
#if defined(ARCH_PORTDUINO)
|
|
// Portduino version
|
|
#include "PortduinoFS.h"
|
|
#define FSCom PortduinoFS
|
|
#define FSBegin() true
|
|
#define FILE_O_WRITE "w"
|
|
#define FILE_O_READ "r"
|
|
#endif
|
|
|
|
#if defined(ARCH_STM32)
|
|
// STM32
|
|
#include "LittleFS.h"
|
|
#define FSCom InternalFS
|
|
#define FSBegin() FSCom.begin()
|
|
using namespace STM32_LittleFS_Namespace;
|
|
#endif
|
|
|
|
#if defined(ARCH_RP2040)
|
|
// RP2040
|
|
#include "LittleFS.h"
|
|
#define FSCom LittleFS
|
|
#define FSBegin() FSCom.begin() // set autoformat
|
|
#define FILE_O_WRITE "w"
|
|
#define FILE_O_READ "r"
|
|
#endif
|
|
|
|
#if defined(ARCH_ESP32)
|
|
// ESP32 version
|
|
#include "LittleFS.h"
|
|
#define FSCom LittleFS
|
|
#define FSBegin() FSCom.begin(true) // format on failure
|
|
#define FILE_O_WRITE "w"
|
|
#define FILE_O_READ "r"
|
|
#endif
|
|
|
|
#if defined(ARCH_NRF52)
|
|
// NRF52 version
|
|
#include "InternalFileSystem.h"
|
|
#define FSCom InternalFS
|
|
#define FSBegin() FSCom.begin() // InternalFS formats on failure
|
|
using namespace Adafruit_LittleFS_Namespace;
|
|
#endif
|
|
|
|
#if defined(ARCH_NRF54L15)
|
|
// nRF54L15 - Zephyr LittleFS on 36 KB storage_partition (internal RRAM)
|
|
#include "InternalFileSystem.h"
|
|
#define FSCom InternalFS
|
|
#define FSBegin() FSCom.begin()
|
|
using namespace Adafruit_LittleFS_Namespace;
|
|
#endif
|
|
|
|
// Filesystem capacity, in bytes. Only ESP32's LittleFS and the nRF54L15 wrapper expose totalBytes()/usedBytes()
|
|
// directly; the other backends need per-platform work (littlefs v1 traversal, FSInfo, statvfs), so callers must
|
|
// use these helpers rather than reaching into FSCom.
|
|
size_t fsTotalBytes();
|
|
size_t fsUsedBytes();
|
|
|
|
void fsInit();
|
|
bool renameFile(const char *pathFrom, const char *pathTo);
|
|
bool fsFormat();
|
|
std::vector<meshtastic_FileInfo> getFiles(const char *dirname, uint8_t levels, size_t maxCount = 64, bool *wasLimited = nullptr);
|
|
void listDir(const char *dirname, uint8_t levels, bool del = false);
|
|
void rmDir(const char *dirname);
|
|
void setupSDCard();
|
|
|
|
#if defined(HAS_SDCARD) && !defined(SDCARD_USE_SOFT_SPI) && defined(SDCARD_USE_SPI1)
|
|
#include <SPI.h>
|
|
// HSPI bus set up by setupSDCard(). Reuse this for other devices on the same bus.
|
|
extern SPIClass SPI_HSPI;
|
|
#endif |