From 833f950edc1df99609135e6469f3d73c483c5a39 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Thu, 16 Oct 2025 09:36:54 -0500 Subject: [PATCH] Move loadProto and saveProto into FSCommon --- src/FSCommon.cpp | 62 +++++++++++++++++++ src/FSCommon.h | 19 +++++- src/graphics/draw/MenuHandler.cpp | 3 +- .../niche/Utils/CannedMessageStore.cpp | 10 +-- src/mesh/NodeDB.cpp | 62 ------------------- src/mesh/NodeDB.h | 18 ------ src/modules/AdminModule.cpp | 2 +- src/modules/CannedMessageModule.cpp | 10 +-- src/modules/ExternalNotificationModule.cpp | 7 ++- 9 files changed, 97 insertions(+), 96 deletions(-) diff --git a/src/FSCommon.cpp b/src/FSCommon.cpp index f215be80f..a57233e9d 100644 --- a/src/FSCommon.cpp +++ b/src/FSCommon.cpp @@ -10,7 +10,10 @@ */ #include "FSCommon.h" #include "SPILock.h" +#include "SafeFile.h" #include "configuration.h" +#include +#include // Software SPI is used by MUI so disable SD card here until it's also implemented #if defined(HAS_SDCARD) && !defined(SDCARD_USE_SOFT_SPI) @@ -335,4 +338,63 @@ void setupSDCard() LOG_DEBUG("Total space: %lu MB", (uint32_t)(SD.totalBytes() / (1024 * 1024))); LOG_DEBUG("Used space: %lu MB", (uint32_t)(SD.usedBytes() / (1024 * 1024))); #endif +} + +/** Load a protobuf from a file, return LoadFileResult */ +LoadFileResult loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct) +{ + LoadFileResult state = LoadFileResult::OTHER_FAILURE; +#ifdef FSCom + concurrency::LockGuard g(spiLock); + + auto f = FSCom.open(filename, FILE_O_READ); + + if (f) { + LOG_INFO("Load %s", filename); + pb_istream_t stream = {&readcb, &f, protoSize}; + if (fields != &meshtastic_NodeDatabase_msg) // contains a vector object + memset(dest_struct, 0, objSize); + if (!pb_decode(&stream, fields, dest_struct)) { + LOG_ERROR("Error: can't decode protobuf %s", PB_GET_ERROR(&stream)); + state = LoadFileResult::DECODE_FAILED; + } else { + LOG_INFO("Loaded %s successfully", filename); + state = LoadFileResult::LOAD_SUCCESS; + } + f.close(); + } else { + LOG_ERROR("Could not open / read %s", filename); + } +#else + LOG_ERROR("ERROR: Filesystem not implemented"); + state = LoadFileResult::NO_FILESYSTEM; +#endif + return state; +} + +/** Save a protobuf from a file, return true for success */ +bool saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct, bool fullAtomic) +{ + bool okay = false; +#ifdef FSCom + auto f = SafeFile(filename, fullAtomic); + + LOG_INFO("Save %s", filename); + pb_ostream_t stream = {&writecb, static_cast(&f), protoSize}; + + if (!pb_encode(&stream, fields, dest_struct)) { + LOG_ERROR("Error: can't encode protobuf %s", PB_GET_ERROR(&stream)); + } else { + okay = true; + } + + bool writeSucceeded = f.close(); + + if (!okay || !writeSucceeded) { + LOG_ERROR("Can't write prefs!"); + } +#else + LOG_ERROR("ERROR: Filesystem not implemented"); +#endif + return okay; } \ No newline at end of file diff --git a/src/FSCommon.h b/src/FSCommon.h index fdc0b76ec..eb4ada8e7 100644 --- a/src/FSCommon.h +++ b/src/FSCommon.h @@ -3,6 +3,19 @@ #include "configuration.h" #include +enum LoadFileResult { + // Successfully opened the file + LOAD_SUCCESS = 1, + // File does not exist + NOT_FOUND = 2, + // Device does not have a filesystem + NO_FILESYSTEM = 3, + // File exists, but could not decode protobufs + DECODE_FAILED = 4, + // File exists, but open failed for some reason + OTHER_FAILURE = 5 +}; + // Cross platform filesystem API #if defined(ARCH_PORTDUINO) @@ -55,4 +68,8 @@ bool renameFile(const char *pathFrom, const char *pathTo); std::vector getFiles(const char *dirname, uint8_t levels); void listDir(const char *dirname, uint8_t levels, bool del = false); void rmDir(const char *dirname); -void setupSDCard(); \ No newline at end of file +void setupSDCard(); +LoadFileResult loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct); + +bool saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct, + bool fullAtomic = true); \ No newline at end of file diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp index 701062e08..4677b0891 100644 --- a/src/graphics/draw/MenuHandler.cpp +++ b/src/graphics/draw/MenuHandler.cpp @@ -1,6 +1,7 @@ #include "configuration.h" #if HAS_SCREEN #include "ClockRenderer.h" +#include "FSCommon.h" #include "GPS.h" #include "MenuHandler.h" #include "MeshRadio.h" @@ -1700,7 +1701,7 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display) void menuHandler::saveUIConfig() { - nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uiconfig); + saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uiconfig); } } // namespace graphics diff --git a/src/graphics/niche/Utils/CannedMessageStore.cpp b/src/graphics/niche/Utils/CannedMessageStore.cpp index 50998930d..cf1533c62 100644 --- a/src/graphics/niche/Utils/CannedMessageStore.cpp +++ b/src/graphics/niche/Utils/CannedMessageStore.cpp @@ -53,9 +53,9 @@ void CannedMessageStore::load() // Attempt to load the bulk canned message data from flash meshtastic_CannedMessageModuleConfig cannedMessageModuleConfig; - LoadFileResult result = nodeDB->loadProto("/prefs/cannedConf.proto", meshtastic_CannedMessageModuleConfig_size, - sizeof(meshtastic_CannedMessageModuleConfig), - &meshtastic_CannedMessageModuleConfig_msg, &cannedMessageModuleConfig); + LoadFileResult result = loadProto("/prefs/cannedConf.proto", meshtastic_CannedMessageModuleConfig_size, + sizeof(meshtastic_CannedMessageModuleConfig), &meshtastic_CannedMessageModuleConfig_msg, + &cannedMessageModuleConfig); // Abort if nothing to load if (result != LoadFileResult::LOAD_SUCCESS || strlen(cannedMessageModuleConfig.messages) == 0) @@ -129,8 +129,8 @@ void CannedMessageStore::handleSet(const meshtastic_AdminMessage *request) #endif // Write to flash - nodeDB->saveProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size, - &meshtastic_CannedMessageModuleConfig_msg, &cannedMessageModuleConfig); + saveProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size, &meshtastic_CannedMessageModuleConfig_msg, + &cannedMessageModuleConfig); // Reload from flash, to update the canned messages in RAM // (This is a lazy way to handle it) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index dec8411fe..a743439a9 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -15,7 +15,6 @@ #include "RTC.h" #include "Router.h" #include "SPILock.h" -#include "SafeFile.h" #include "TypeConversions.h" #include "error.h" #include "main.h" @@ -1105,39 +1104,6 @@ void NodeDB::pickNewNodeNum() myNodeInfo.my_node_num = nodeNum; } -/** Load a protobuf from a file, return LoadFileResult */ -LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, - void *dest_struct) -{ - LoadFileResult state = LoadFileResult::OTHER_FAILURE; -#ifdef FSCom - concurrency::LockGuard g(spiLock); - - auto f = FSCom.open(filename, FILE_O_READ); - - if (f) { - LOG_INFO("Load %s", filename); - pb_istream_t stream = {&readcb, &f, protoSize}; - if (fields != &meshtastic_NodeDatabase_msg) // contains a vector object - memset(dest_struct, 0, objSize); - if (!pb_decode(&stream, fields, dest_struct)) { - LOG_ERROR("Error: can't decode protobuf %s", PB_GET_ERROR(&stream)); - state = LoadFileResult::DECODE_FAILED; - } else { - LOG_INFO("Loaded %s successfully", filename); - state = LoadFileResult::LOAD_SUCCESS; - } - f.close(); - } else { - LOG_ERROR("Could not open / read %s", filename); - } -#else - LOG_ERROR("ERROR: Filesystem not implemented"); - state = LoadFileResult::NO_FILESYSTEM; -#endif - return state; -} - void NodeDB::loadFromDisk() { // Mark the current device state as completely unusable, so that if we fail reading the entire file from @@ -1351,34 +1317,6 @@ void NodeDB::loadFromDisk() #endif } -/** Save a protobuf from a file, return true for success */ -bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct, - bool fullAtomic) -{ - bool okay = false; -#ifdef FSCom - auto f = SafeFile(filename, fullAtomic); - - LOG_INFO("Save %s", filename); - pb_ostream_t stream = {&writecb, static_cast(&f), protoSize}; - - if (!pb_encode(&stream, fields, dest_struct)) { - LOG_ERROR("Error: can't encode protobuf %s", PB_GET_ERROR(&stream)); - } else { - okay = true; - } - - bool writeSucceeded = f.close(); - - if (!okay || !writeSucceeded) { - LOG_ERROR("Can't write prefs!"); - } -#else - LOG_ERROR("ERROR: Filesystem not implemented"); -#endif - return okay; -} - bool NodeDB::saveChannelsToDisk() { #ifdef FSCom diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index e8724f2c9..42e7c2f75 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -110,19 +110,6 @@ uint32_t sinceLastSeen(const meshtastic_NodeInfoLite *n); /// Given a packet, return how many seconds in the past (vs now) it was received uint32_t sinceReceived(const meshtastic_MeshPacket *p); -enum LoadFileResult { - // Successfully opened the file - LOAD_SUCCESS = 1, - // File does not exist - NOT_FOUND = 2, - // Device does not have a filesystem - NO_FILESYSTEM = 3, - // File exists, but could not decode protobufs - DECODE_FAILED = 4, - // File exists, but open failed for some reason - OTHER_FAILURE = 5 -}; - enum UserLicenseStatus { NotKnown, NotLicensed, Licensed }; class NodeDB @@ -233,11 +220,6 @@ class NodeDB bool factoryReset(bool eraseBleBonds = false); - LoadFileResult loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, - void *dest_struct); - bool saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct, - bool fullAtomic = true); - void installRoleDefaults(meshtastic_Config_DeviceConfig_Role role); const meshtastic_NodeInfoLite *readNextMeshNode(uint32_t &readIndex); diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index d300ff53b..adf74fef5 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -1306,7 +1306,7 @@ void AdminModule::saveChanges(int saveWhat, bool shouldReboot) void AdminModule::handleStoreDeviceUIConfig(const meshtastic_DeviceUIConfig &uicfg) { - nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uicfg); + saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg, &uicfg); } void AdminModule::handleSetHamMode(const meshtastic_HamParameters &p) diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index e9f52bb7d..fad8bd54c 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -2185,9 +2185,9 @@ ProcessMessage CannedMessageModule::handleReceived(const meshtastic_MeshPacket & void CannedMessageModule::loadProtoForModule() { - if (nodeDB->loadProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size, - sizeof(meshtastic_CannedMessageModuleConfig), &meshtastic_CannedMessageModuleConfig_msg, - &cannedMessageModuleConfig) != LoadFileResult::LOAD_SUCCESS) { + if (loadProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size, + sizeof(meshtastic_CannedMessageModuleConfig), &meshtastic_CannedMessageModuleConfig_msg, + &cannedMessageModuleConfig) != LoadFileResult::LOAD_SUCCESS) { installDefaultCannedMessageModuleConfig(); } } @@ -2207,8 +2207,8 @@ bool CannedMessageModule::saveProtoForModule() spiLock->unlock(); #endif - okay &= nodeDB->saveProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size, - &meshtastic_CannedMessageModuleConfig_msg, &cannedMessageModuleConfig); + okay &= saveProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size, + &meshtastic_CannedMessageModuleConfig_msg, &cannedMessageModuleConfig); return okay; } diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index ffc789275..a97a137eb 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -14,6 +14,7 @@ * @date [Insert Date] */ #include "ExternalNotificationModule.h" +#include "FSCommon.h" #include "MeshService.h" #include "NodeDB.h" #include "RTC.h" @@ -370,8 +371,8 @@ ExternalNotificationModule::ExternalNotificationModule() if (inputBroker) // put our callback in the inputObserver list inputObserver.observe(inputBroker); #endif - if (nodeDB->loadProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, sizeof(meshtastic_RTTTLConfig), - &meshtastic_RTTTLConfig_msg, &rtttlConfig) != LoadFileResult::LOAD_SUCCESS) { + if (loadProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, sizeof(meshtastic_RTTTLConfig), &meshtastic_RTTTLConfig_msg, + &rtttlConfig) != LoadFileResult::LOAD_SUCCESS) { memset(rtttlConfig.ringtone, 0, sizeof(rtttlConfig.ringtone)); // The default ringtone is always loaded from userPrefs.jsonc strncpy(rtttlConfig.ringtone, USERPREFS_RINGTONE_RTTTL, sizeof(rtttlConfig.ringtone)); @@ -627,7 +628,7 @@ void ExternalNotificationModule::handleSetRingtone(const char *from_msg) } if (changed) { - nodeDB->saveProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, &meshtastic_RTTTLConfig_msg, &rtttlConfig); + saveProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, &meshtastic_RTTTLConfig_msg, &rtttlConfig); } }