The BaseNvs class provides a comprehensive non-volatile storage abstraction that serves as the
unified interface for all persistent data operations in the HardFOC system.
It supports key-value storage, multiple data types, namespaces,
and works across different storage implementations.
โจ Key Features
๐พ Key-Value Storage - Simple and efficient key-value pairs
๐ Multiple Data Types - uint32_t, strings, binary blobs
๐๏ธ Namespace Support - Organized storage with namespaces
๐ Atomic Operations - Safe concurrent access
๐ก๏ธ Robust Error Handling - Comprehensive validation and error reporting
๐ Platform Agnostic - Works with flash, EEPROM, and other storage
๐ Statistics & Diagnostics - Built-in monitoring and health reporting
๐งต Thread Safe - Designed for multi-threaded applications
/**
* @brief Initialize the NVS storage system
* @return hf_nvs_err_t error code
*
* ๐ Sets up storage hardware, opens namespace, and prepares for operations.
* Must be called before any storage operations.
*
* @example
* EspNvs nvs("config");
* if (nvs.Initialize() == hf_nvs_err_t::NVS_SUCCESS) {
* // NVS ready for use
* }
*/virtualhf_nvs_err_tInitialize()noexcept=0;/**
* @brief Deinitialize the NVS storage system
* @return hf_nvs_err_t error code
*
* ๐งน Cleanly shuts down storage and closes namespace.
*/virtualhf_nvs_err_tDeinitialize()noexcept=0;/**
* @brief Check if NVS is initialized
* @return true if initialized, false otherwise
*
* โ Query initialization status without side effects.
*/boolIsInitialized()constnoexcept;/**
* @brief Ensure NVS is initialized (lazy initialization)
* @return true if initialized successfully, false otherwise
*
* ๐ Automatically initializes NVS if not already initialized.
*/boolEnsureInitialized();/**
* @brief Ensure NVS is deinitialized (lazy deinitialization)
* @return true if deinitialized successfully, false otherwise
*
* ๐ Automatically deinitializes NVS if currently initialized.
*/boolEnsureDeinitialized();
/**
* @brief Erase specific key
* @param key Storage key to erase
* @return hf_nvs_err_t error code
*
* ๐๏ธ Removes a specific key-value pair from storage.
*
* @example
* hf_nvs_err_t result = nvs.EraseKey("obsolete_config");
* if (result == hf_nvs_err_t::NVS_SUCCESS) {
* printf("Key erased successfully\n");
* }
*/virtualhf_nvs_err_tEraseKey(constchar*key)noexcept=0;/**
* @brief Erase all data in namespace
* @return hf_nvs_err_t error code
*
* ๐๏ธ Removes all key-value pairs in the current namespace.
*
* @example
* hf_nvs_err_t result = nvs.EraseAll();
* if (result == hf_nvs_err_t::NVS_SUCCESS) {
* printf("All data erased successfully\n");
* }
*/virtualhf_nvs_err_tEraseAll()noexcept=0;/**
* @brief Get size of stored value
* @param key Storage key
* @param size Reference to store size
* @return hf_nvs_err_t error code
*
* ๐ Gets the size of a stored value without reading it.
*
* @example
* size_t value_size;
* hf_nvs_err_t result = nvs.GetSize("config", value_size);
* if (result == hf_nvs_err_t::NVS_SUCCESS) {
* printf("Config size: %zu bytes\n", value_size);
* }
*/virtualhf_nvs_err_tGetSize(constchar*key,size_t&size)noexcept=0;
๐ Information Methods
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* @brief Get maximum key length
* @return Maximum key length in characters
*
* ๐ Returns the maximum allowed key length for this storage.
*/virtualsize_tGetMaxKeyLength()constnoexcept=0;/**
* @brief Get maximum value size
* @return Maximum value size in bytes
*
* ๐ Returns the maximum allowed value size for this storage.
*/virtualsize_tGetMaxValueSize()constnoexcept=0;
/**
* @brief Reset NVS operation statistics
* @return hf_nvs_err_t error code
*
* ๐ Clears all accumulated statistics counters.
*/virtualhf_nvs_err_tResetStatistics()noexcept;/**
* @brief Reset NVS diagnostic information
* @return hf_nvs_err_t error code
*
* ๐ Clears diagnostic information and error counters.
*/virtualhf_nvs_err_tResetDiagnostics()noexcept;/**
* @brief Get NVS operation statistics
* @param statistics Reference to store statistics data
* @return hf_nvs_err_t error code
*
* ๐ Retrieves comprehensive statistics about NVS operations.
*/virtualhf_nvs_err_tGetStatistics(hf_nvs_statistics_t&statistics)constnoexcept;/**
* @brief Get NVS diagnostic information
* @param diagnostics Reference to store diagnostics data
* @return hf_nvs_err_t error code
*
* ๐ Retrieves diagnostic information about NVS health and status.
*/virtualhf_nvs_err_tGetDiagnostics(hf_nvs_diagnostics_t&diagnostics)constnoexcept;
๐ Data Structures
๐ NVS Statistics Structure
1
2
3
4
5
6
7
8
9
10
11
12
13
14
structhf_nvs_statistics_t{uint32_ttotal_operations;///< Total operations performeduint32_ttotal_errors;///< Total errors encountereduint32_ttotal_reads;///< Total read operationsuint32_ttotal_writes;///< Total write operationsuint32_ttotal_commits;///< Total commit operationsuint32_ttotal_erases;///< Total erase operationshf_nvs_err_tlast_error;///< Last error encountereduint32_tlast_operation_time_us;///< Time of last operationuint32_tsuccessful_ops;///< Successful operationsuint32_tfailed_ops;///< Failed operationsuint32_tbytes_written;///< Total bytes writtenuint32_tbytes_read;///< Total bytes read};
๐ NVS Diagnostics Structure
1
2
3
4
5
6
structhf_nvs_diagnostics_t{hf_nvs_err_tlast_error;///< Last error encountereduint32_tconsecutive_errors;///< Consecutive error countboolstorage_healthy;///< Storage health statusuint32_tsystem_uptime_ms;///< System uptime in milliseconds};
#include"mcu/esp32/EspNvs.h"classCalibrationManager{private:EspNvscalib_nvs*;public:CalibrationManager():calib_nvs*("calibration"){}boolinitialize(){returncalib_nvs*.EnsureInitialized();}boolsave_adc_calibration(constAdcCalibration&calib){// Store calibration data as blobhf_nvs_err_tresult=calib_nvs*.SetBlob("adc_calib",&calib,sizeof(calib));if(result!=hf_nvs_err_t::NVS_SUCCESS){printf("โ Failed to save ADC calibration: %s\n",HfNvsErrToString(result));returnfalse;}// Store calibration timestampuint32_ttimestamp=static_cast<uint32_t>(time(nullptr));result=calib_nvs*.SetU32("adc_calib_time",timestamp);if(result!=hf_nvs_err_t::NVS_SUCCESS){printf("โ Failed to save calibration timestamp: %s\n",HfNvsErrToString(result));returnfalse;}printf("โ ADC calibration saved successfully\n");returntrue;}boolload_adc_calibration(AdcCalibration&calib){// Check if calibration existssize_tcalib_size;hf_nvs_err_tresult=calib_nvs*.GetSize("adc_calib",calib_size);if(result!=hf_nvs_err_t::NVS_SUCCESS){printf("โ Calibration not found\n");returnfalse;}if(calib_size!=sizeof(AdcCalibration)){printf("โ Calibration size mismatch: expected %zu, got %zu\n",sizeof(AdcCalibration),calib_size);returnfalse;}// Load calibration dataresult=calib_nvs*.GetBlob("adc_calib",&calib,sizeof(calib));if(result!=hf_nvs_err_t::NVS_SUCCESS){printf("โ Failed to load ADC calibration: %s\n",HfNvsErrToString(result));returnfalse;}// Load and check timestampuint32_ttimestamp;result=calib_nvs*.GetU32("adc_calib_time",timestamp);if(result==hf_nvs_err_t::NVS_SUCCESS){uint32_tcurrent_time=static_cast<uint32_t>(time(nullptr));uint32_tage_days=(current_time-timestamp)/(24*3600);printf("โ ADC calibration loaded (age: %u days)\n",age_days);if(age_days>30){printf("โ ๏ธ Calibration is old (%u days), consider re-calibration\n",age_days);}}returntrue;}boolis_calibration_valid(){size_tcalib_size;hf_nvs_err_tresult=calib_nvs*.GetSize("adc_calib",calib_size);return(result==hf_nvs_err_t::NVS_SUCCESS&&calib_size==sizeof(AdcCalibration));}voidclear_calibration(){calib_nvs*.EraseKey("adc_calib");calib_nvs*.EraseKey("adc_calib_time");printf("๐๏ธ Calibration data cleared\n");}};structAdcCalibration{floatgain_coefficients[8];floatoffset_coefficients[8];floattemperature_coefficient;uint32_tcalibration_date;uint16_tchecksum;};
#include"mcu/esp32/EspNvs.h"classLogManager{private:EspNvslog_nvs*;uint32_tlog_index*;public:LogManager():log_nvs*("logs"),log_index*(0){}boolinitialize(){if(!log_nvs*.EnsureInitialized()){returnfalse;}// Load current log indexhf_nvs_err_tresult=log_nvs*.GetU32("log_index",log_index*);if(result==hf_nvs_err_t::NVS_ERR_KEY_NOT_FOUND){log_index*=0;// Start from beginning}elseif(result!=hf_nvs_err_t::NVS_SUCCESS){printf("โ Failed to load log index: %s\n",HfNvsErrToString(result));returnfalse;}returntrue;}booladd_log_entry(constchar*message){charkey[16];snprintf(key,sizeof(key),"log*%u",log_index*);// Store log messagehf_nvs_err_tresult=log_nvs*.SetString(key,message);if(result!=hf_nvs_err_t::NVS_SUCCESS){printf("โ Failed to store log entry: %s\n",HfNvsErrToString(result));returnfalse;}// Increment and save log indexlog_index*++;result=log_nvs*.SetU32("log_index",log_index*);if(result!=hf_nvs_err_t::NVS_SUCCESS){printf("โ Failed to update log index: %s\n",HfNvsErrToString(result));returnfalse;}printf("โ Log entry %u stored: %s\n",log_index*-1,message);returntrue;}voidprint_recent_logs(uint32_tcount=10){printf("๐ Recent Log Entries:\n");printf("=====================\n");uint32_tstart_index=(log_index*>count)?(log_index*-count):0;for(uint32_ti=start_index;i<log_index*;i++){charkey[16];snprintf(key,sizeof(key),"log*%u",i);charmessage[128];hf_nvs_err_tresult=log_nvs*.GetString(key,message,sizeof(message));if(result==hf_nvs_err_t::NVS_SUCCESS){printf("[%u] %s\n",i,message);}else{printf("[%u] <log entry not found>\n",i);}}}voidclear_logs(){// Erase all log entriesfor(uint32_ti=0;i<log_index*;i++){charkey[16];snprintf(key,sizeof(key),"log*%u",i);log_nvs*.EraseKey(key);}// Reset log indexlog_index*=0;log_nvs*.SetU32("log_index",log_index*);printf("๐๏ธ All logs cleared\n");}uint32_tget_log_count()const{returnlog_index*;}};
#include"mcu/esp32/EspNvs.h"classSecureStorage{private:EspNvssecure_nvs*;public:SecureStorage():secure_nvs*("secure"){}boolinitialize(){if(!secure_nvs*.EnsureInitialized()){returnfalse;}// Enable encryption if supportedhf_nvs_err_tresult=secure_nvs*.SetEncryption(true);if(result==hf_nvs_err_t::NVS_SUCCESS){printf("โ Encryption enabled\n");}elseif(result==hf_nvs_err_t::NVS_ERR_ENCRYPTION_NOT_SUPPORTED){printf("โ ๏ธ Encryption not supported on this storage\n");}else{printf("โ Failed to enable encryption: %s\n",HfNvsErrToString(result));returnfalse;}returntrue;}boolstore_credentials(constchar*username,constchar*password){// Store usernamehf_nvs_err_tresult=secure_nvs*.SetString("username",username);if(result!=hf_nvs_err_t::NVS_SUCCESS){printf("โ Failed to store username: %s\n",HfNvsErrToString(result));returnfalse;}// Store passwordresult=secure_nvs*.SetString("password",password);if(result!=hf_nvs_err_t::NVS_SUCCESS){printf("โ Failed to store password: %s\n",HfNvsErrToString(result));returnfalse;}printf("โ Credentials stored securely\n");returntrue;}boolload_credentials(char*username,size_tusername_size,char*password,size_tpassword_size){// Load usernamehf_nvs_err_tresult=secure_nvs*.GetString("username",username,username_size);if(result!=hf_nvs_err_t::NVS_SUCCESS){printf("โ Failed to load username: %s\n",HfNvsErrToString(result));returnfalse;}// Load passwordresult=secure_nvs*.GetString("password",password,password_size);if(result!=hf_nvs_err_t::NVS_SUCCESS){printf("โ Failed to load password: %s\n",HfNvsErrToString(result));returnfalse;}printf("โ Credentials loaded successfully\n");returntrue;}voidclear_credentials(){secure_nvs*.EraseKey("username");secure_nvs*.EraseKey("password");printf("๐๏ธ Credentials cleared\n");}};
// โ Always check initializationif(!nvs.EnsureInitialized()){printf("โ NVS initialization failed\n");returnfalse;}// โ Use appropriate error handlinguint32_tvalue;hf_nvs_err_tresult=nvs.GetU32("key",value);if(result==hf_nvs_err_t::NVS_SUCCESS){// Use the value}elseif(result==hf_nvs_err_t::NVS_ERR_KEY_NOT_FOUND){// Key doesn't exist, use defaultvalue=default_value;}else{printf("โ NVS Error: %s\n",HfNvsErrToString(result));returnfalse;}// โ Check data sizes before operationssize_trequired_size;if(nvs.GetSize("key",required_size)==hf_nvs_err_t::NVS_SUCCESS){if(required_size>buffer_size){printf("โ Buffer too small, need %zu bytes\n",required_size);returnfalse;}}// โ Use namespaces for organizationEspNvsconfig_nvs("config");EspNvscalib_nvs("calibration");EspNvslogs_nvs("logs");// โ Validate data integrityuint16_tstored_checksum;if(nvs.GetU32("checksum",stored_checksum)==hf_nvs_err_t::NVS_SUCCESS){uint16_tcalculated_checksum=calculate_checksum(data,size);if(stored_checksum!=calculated_checksum){printf("โ Data integrity check failed\n");returnfalse;}}// โ Monitor storage healthhf_nvs_statistics_tstats;if(nvs.GetStatistics(stats)==hf_nvs_err_t::NVS_SUCCESS){if(stats.failed_ops>10){printf("โ ๏ธ High NVS failure rate detected\n");}}
โ Common Pitfalls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// โ Don't ignore initializationnvs.SetU32("key",value);// May fail silently// โ Don't ignore error codesnvs.GetString("key",buffer,size);// Error handling missing// โ Don't assume key existsuint32_tvalue=nvs.GetU32("key");// May return garbage// โ Don't use without checking buffer sizescharbuffer[16];nvs.GetString("key",buffer,sizeof(buffer));// May truncate// โ Don't store sensitive data unencryptednvs.SetString("password","secret");// Use encrypted storage// โ Don't ignore storage capacity// Check available space before large writes
// ๐ Use appropriate data types// Use uint32_t for small integers// Use blobs for large data structures// Use strings for text data// ๐ Minimize write operations// Batch related data together// Use atomic operations where possible// ๐ Use appropriate key names// Keep keys short but descriptive// Use consistent naming conventions// ๐ Monitor storage usagehf_nvs_statistics_tstats;nvs.GetStatistics(stats);if(stats.bytes_written>max_storage_bytes){printf("โ ๏ธ Storage usage high: %u bytes\n",stats.bytes_written);}// ๐ Use encryption for sensitive data// Enable encryption when available// Store encryption keys securely// ๐ Implement data validation// Use checksums for data integrity// Validate data ranges and formats