diff --git a/src/FSCommon.cpp b/src/FSCommon.cpp index f215be80fb6..c274959bbb6 100644 --- a/src/FSCommon.cpp +++ b/src/FSCommon.cpp @@ -80,10 +80,11 @@ bool renameFile(const char *pathFrom, const char *pathTo) { #ifdef FSCom -#ifdef ARCH_ESP32 +#if defined(ARCH_ESP32) || defined(ARCH_STM32WL) // take SPI Lock spiLock->lock(); - // rename was fixed for ESP32 IDF LittleFS in April + // ESP32: rename was fixed for IDF LittleFS in April + // STM32WL: STM32_LittleFS::rename() calls lfs_rename() which is atomic bool result = FSCom.rename(pathFrom, pathTo); spiLock->unlock(); return result; @@ -271,8 +272,8 @@ void rmDir(const char *dirname) #if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO)) listDir(dirname, 10, true); -#elif defined(ARCH_NRF52) - // nRF52 implementation of LittleFS has a recursive delete function +#elif defined(ARCH_NRF52) || defined(ARCH_STM32WL) + // nRF52 and STM32WL implementations of LittleFS have a recursive delete function FSCom.rmdir_r(dirname); #endif diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 4b08715660f..cf77e5beb35 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1604,7 +1604,8 @@ bool NodeDB::saveToDisk(int saveWhat) if (!success) { LOG_ERROR("Failed to save to disk, retrying"); -#ifdef ARCH_NRF52 // @geeksville is not ready yet to say we should do this on other platforms. See bug #4184 discussion +#if defined(ARCH_NRF52) || \ + defined(ARCH_STM32WL) // @geeksville is not ready yet to say we should do this on other platforms. See bug #4184 discussion spiLock->lock(); FSCom.format(); spiLock->unlock(); @@ -2189,6 +2190,7 @@ bool NodeDB::checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_pub } #endif +#if !MESHTASTIC_EXCLUDE_BACKUP bool NodeDB::backupPreferences(meshtastic_AdminMessage_BackupLocation location) { bool success = false; @@ -2276,6 +2278,7 @@ bool NodeDB::restorePreferences(meshtastic_AdminMessage_BackupLocation location, #endif return success; } +#endif // !MESHTASTIC_EXCLUDE_BACKUP /// Record an error that should be reported via analytics void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, const char *filename) diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index f6be963c184..b73c786fc2f 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -102,7 +102,9 @@ static constexpr const char *configFileName = "/prefs/config.proto"; static constexpr const char *uiconfigFileName = "/prefs/uiconfig.proto"; static constexpr const char *moduleConfigFileName = "/prefs/module.proto"; static constexpr const char *channelFileName = "/prefs/channels.proto"; +#if !MESHTASTIC_EXCLUDE_BACKUP static constexpr const char *backupFileName = "/backups/backup.proto"; +#endif /// Given a node, return how many seconds in the past (vs now) that we last heard from it uint32_t sinceLastSeen(const meshtastic_NodeInfoLite *n); @@ -316,9 +318,11 @@ class NodeDB bool checkLowEntropyPublicKey(const meshtastic_Config_SecurityConfig_public_key_t &keyToTest); #endif +#if !MESHTASTIC_EXCLUDE_BACKUP bool backupPreferences(meshtastic_AdminMessage_BackupLocation location); bool restorePreferences(meshtastic_AdminMessage_BackupLocation location, int restoreWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS); +#endif /// Notify observers of changes to the DB void notifyObservers(bool forceUpdate = false) @@ -331,9 +335,11 @@ class NodeDB private: bool duplicateWarned = false; bool localPositionUpdatedSinceBoot = false; - uint32_t lastNodeDbSave = 0; // when we last saved our db to flash + uint32_t lastNodeDbSave = 0; // when we last saved our db to flash +#if !MESHTASTIC_EXCLUDE_BACKUP uint32_t lastBackupAttempt = 0; // when we last tried a backup automatically or manually - uint32_t lastSort = 0; // When last sorted the nodeDB +#endif + uint32_t lastSort = 0; // When last sorted the nodeDB /// Find a node in our DB, create an empty NodeInfoLite if missing meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n); diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 05bc0aa5d84..c06a39e840b 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -499,6 +499,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta #endif break; } +#if !MESHTASTIC_EXCLUDE_BACKUP case meshtastic_AdminMessage_backup_preferences_tag: { LOG_INFO("Client requesting to backup preferences"); if (nodeDB->backupPreferences(r->backup_preferences)) { @@ -535,6 +536,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta #endif break; } +#endif // !MESHTASTIC_EXCLUDE_BACKUP case meshtastic_AdminMessage_send_input_event_tag: { LOG_INFO("Client requesting to send input event"); handleSendInputEvent(r->send_input_event); diff --git a/src/platform/stm32wl/LittleFS.cpp b/src/platform/stm32wl/LittleFS.cpp index 40f32eca89d..1736d0907f5 100644 --- a/src/platform/stm32wl/LittleFS.cpp +++ b/src/platform/stm32wl/LittleFS.cpp @@ -83,31 +83,36 @@ static int _internal_flash_prog(const struct lfs_config *c, lfs_block_t block, l LFS_UNUSED(c); + // STM32WL HAL minimum write unit is one 64-bit doubleword (8 bytes) + if (size % 8 != 0) { + return LFS_ERR_INVAL; + } + _LFS_DBG("Programming %d bytes/%d doublewords at address 0x%08x/block %d, offset %d.", size, dw_count, address, block, off); + + // Validate the full write range before touching flash + lfs_block_t addr_end = address + (lfs_block_t)(dw_count * 8) - 1; + if ((address < LFS_FLASH_ADDR_BASE) || (addr_end > LFS_FLASH_ADDR_END)) { + _LFS_DBG("Wanted to program out of bound of FLASH: 0x%08x-0x%08x.\n", address, addr_end); + return LFS_ERR_INVAL; + } + if (HAL_FLASH_Unlock() != HAL_OK) { return LFS_ERR_IO; } + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); for (uint32_t i = 0; i < dw_count; i++) { - if ((address < LFS_FLASH_ADDR_BASE) || (address > LFS_FLASH_ADDR_END)) { - _LFS_DBG("Wanted to program out of bound of FLASH: 0x%08x.\n", address); - HAL_FLASH_Lock(); - return LFS_ERR_INVAL; - } hal_rc = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, *bufp); if (hal_rc != HAL_OK) { - /* Error occurred while writing data in Flash memory. - * User can add here some code to deal with this error. - */ _LFS_DBG("Program error at (0x%08x), 0x%X, error: 0x%08x\n", address, hal_rc, HAL_FLASH_GetError()); + break; // Do not continue programming after a failure } address += 8; bufp += 1; } - if (HAL_FLASH_Lock() != HAL_OK) { - return LFS_ERR_IO; - } + HAL_FLASH_Lock(); - return hal_rc == HAL_OK ? LFS_ERR_OK : LFS_ERR_IO; // If HAL_OK, return LFS_ERR_OK, else return LFS_ERR_IO + return hal_rc == HAL_OK ? LFS_ERR_OK : LFS_ERR_IO; } // Erase a block. A block must be erased before being programmed. @@ -130,7 +135,10 @@ static int _internal_flash_erase(const struct lfs_config *c, lfs_block_t block) /* calculate the absolute page, i.e. what the ST wants */ EraseInitStruct.Page = (address - STM32WL_FLASH_BASE) / STM32WL_PAGE_SIZE; _LFS_DBG("Erasing block %d at 0x%08x... ", block, address); - HAL_FLASH_Unlock(); + if (HAL_FLASH_Unlock() != HAL_OK) { + return LFS_ERR_IO; + } + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); hal_rc = HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError); HAL_FLASH_Lock(); diff --git a/variants/stm32/stm32.ini b/variants/stm32/stm32.ini index 542d0880065..515608b51e3 100644 --- a/variants/stm32/stm32.ini +++ b/variants/stm32/stm32.ini @@ -25,6 +25,7 @@ build_flags = -DMESHTASTIC_EXCLUDE_BLUETOOTH=1 -DMESHTASTIC_EXCLUDE_WIFI=1 -DMESHTASTIC_EXCLUDE_TZ=1 ; Exclude TZ to save some flash space. + -DMESHTASTIC_EXCLUDE_BACKUP=1 ; Backup preferences require 2 flash blocks (4 KB); not useful on a flash-constrained node. -DSERIAL_RX_BUFFER_SIZE=256 ; For GPS - the default of 64 is too small. -DHAS_SCREEN=0 ; Always disable screen for STM32, it is not supported. ;-DPIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF ; Enable this if enabling debugg logging. It is REQUIRED for at least traceroute debug prints - without it the length returned by printf ends up uninitialized.