Bluenet  5.7.0
Bluenet, firmware for nRF52 smart home devices
Loading...
Searching...
No Matches
Storage Class Reference

Class to store items persistently in flash (persistent) memory. More...

#include <cs_Storage.h>

Public Member Functions

cs_ret_code_t init ()
 
bool isInitialized ()
 
bool isBusy ()
 
void setErrorCallback (cs_storage_error_callback_t callback)
 Set the callback for errors. More...
 
cs_ret_code_t findFirst (CS_TYPE type, cs_state_id_t &id)
 Find first id of stored values of given type. More...
 
cs_ret_code_t findNext (CS_TYPE type, cs_state_id_t &id)
 Find next id of stored values of given type. More...
 
cs_ret_code_t read (cs_state_data_t &data)
 Find and read stored value of given type and id. More...
 
cs_ret_code_t readV3ResetCounter (cs_state_data_t &data)
 Read the old (v3) reset counter. More...
 
cs_ret_code_t readFirst (cs_state_data_t &data)
 Find and read from first stored value of given type. More...
 
cs_ret_code_t readNext (cs_state_data_t &data)
 Find and read next stored value of given type. More...
 
cs_ret_code_t write (const cs_state_data_t &data)
 Write to persistent storage. More...
 
cs_ret_code_t remove (CS_TYPE type, cs_state_id_t id)
 Remove value of given type and id. More...
 
cs_ret_code_t remove (CS_TYPE type)
 Remove all values of a type. More...
 
cs_ret_code_t remove (cs_state_id_t id)
 Remove all values with given id. More...
 
cs_ret_code_t factoryReset ()
 Perform factory reset. More...
 
cs_ret_code_t garbageCollect ()
 Garbage collection reclaims the flash space that is occupied by records that have been deleted, or that failed to be completely written due to, for example, a power loss. More...
 
cs_ret_code_t eraseAllPages ()
 Erase all flash pages used by FDS. More...
 
cs_ret_code_t erasePages (const CS_TYPE doneEvent, void *startAddress, void *endAddress)
 Erase flash pages. More...
 
uint8_t * allocate (size16_t &size)
 Allocate ram that is correctly aligned and padded. More...
 
void handleFileStorageEvent (fds_evt_t const *p_fds_evt)
 Handle FDS events. More...
 
void handleFlashOperationSuccess ()
 Handle FDS SOC event NRF_EVT_FLASH_OPERATION_SUCCESS. More...
 
void handleFlashOperationError ()
 Handle FDS SOC event NRF_EVT_FLASH_OPERATION_ERROR. More...
 

Static Public Member Functions

static StoragegetInstance ()
 Returns the singleton instance of this class. More...
 

Private Member Functions

 Storage ()=default
 
 Storage (Storage const &)=delete
 
void operator= (Storage const &)=delete
 
cs_ret_code_t findNextInternal (uint16_t recordKey, uint16_t &fileId)
 Find next fileId for given recordKey. More...
 
cs_ret_code_t readNextInternal (uint16_t recordKey, uint16_t &fileId, uint8_t *buf, uint16_t size)
 Read next fileId for given recordKey. More...
 
cs_ret_code_t readRecord (fds_record_desc_t recordDesc, uint8_t *buf, uint16_t size, uint16_t &fileId)
 Read a record: copy data to buffer, and sets fileId. More...
 
ret_code_t writeInternal (const cs_state_data_t &data)
 Write to persistent storage. More...
 
ret_code_t garbageCollectInternal ()
 
bool isErasingPages ()
 
void eraseNextPage ()
 Erase next page, started via eraseAllPages(). More...
 
cs_ret_code_t continueFactoryReset ()
 Continue the factory reset process. More...
 
size16_t getPaddedSize (size16_t size)
 Returns size after padding for flash. More...
 
uint16_t getFileId (cs_state_id_t valueId)
 Get file id, given state value id. More...
 
cs_state_id_t getStateId (uint16_t fileId)
 Get state value id, given file id. More...
 
bool isValidRecordKey (uint16_t recordKey)
 
bool isValidFileId (uint16_t fileId)
 
void initSearch (CS_TYPE type)
 Start a new search, where the user wants to iterate over a certain type. More...
 
void initSearch ()
 Start a new search. More...
 
ret_code_t exists (cs_file_id_t file_id, uint16_t recordKey, fds_record_desc_t &record_desc, bool &result)
 Check if a type of record exists and return the record descriptor. More...
 
void setBusy (uint16_t recordKey)
 
void clearBusy (uint16_t recordKey)
 
bool isBusy (uint16_t recordKey)
 
cs_ret_code_t getErrorCode (ret_code_t code)
 
void handleWriteEvent (fds_evt_t const *p_fds_evt)
 
void handleRemoveRecordEvent (fds_evt_t const *p_fds_evt)
 
void handleRemoveFileEvent (fds_evt_t const *p_fds_evt)
 
void handleGarbageCollectionEvent (fds_evt_t const *p_fds_evt)
 

Private Attributes

bool _initialized = false
 
bool _registeredFds = false
 
cs_storage_error_callback_t _errorCallback = NULL
 
fds_find_token_t _findToken
 
CS_TYPE _currentSearchType = CS_TYPE::CONFIG_DO_NOT_USE
 
bool _collectingGarbage = false
 
bool _removingFile = false
 
bool _performingFactoryReset = false
 
std::vector< uint16_t > _busyRecordKeys
 
uint32_t _erasePage = 0
 Next page to erase. More...
 
uint32_t _eraseEndPage = 0
 Page that should not be erased. More...
 
CS_TYPE _eraseDoneEvent = CS_TYPE::CONFIG_DO_NOT_USE
 

Friends

class TestAccess< Storage >
 

Detailed Description

Class to store items persistently in flash (persistent) memory.

This class provides functions to initialize, clear, write and read persistent memory (flash) through the use of Flash Data Storage.

The information on the Flash Data Storage from Nordic can be found at the link: https://www.nordicsemi.com/DocLib/Content/SDK_Doc/nRF5_SDK/v15-2-0/lib_fds old: https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk%2Fdita%2Fsdk%2Fnrf5_sdk.html

CS_TYPE is used as record key.

Garbage collection will be automatically started by this class when needed.

When a record is corrupted, most likely in case of power loss while writing, the CRC check will fail when opening a file. In this case the record will be deleted (TODO).

Only one record for each record key should exist. In case there are multiple (duplicates), they will be removed (TODO). Since FDS always appends records, it is assumed that the last valid record should be kept. Checking for duplicates is done for each write and each read.

Some operations will block other operations. For example, you can't write a record while performing garbage collection. You can't write a record while it's already being written. This is what the "busy" functions are for. Each type can be set busy multiple times, for example in case multiple records of the same type are being deleted.

FDS internally uses events NRF_EVT_FLASH_OPERATION_SUCCESS and NRF_EVT_FLASH_OPERATION_ERROR. These events don't give any context of the operation, so it is not adviced to use FDS together with something else that writes to flash (like Flash Manager).

Constructor & Destructor Documentation

◆ Storage() [1/2]

Storage::Storage ( )
privatedefault

◆ Storage() [2/2]

Storage::Storage ( Storage const &  )
privatedelete

Member Function Documentation

◆ allocate()

uint8_t * Storage::allocate ( size16_t size)

Allocate ram that is correctly aligned and padded.

Parameters
[in,out]sizeRequested size, afterwards set to the allocated size.
Returns
Pointer to allocated memory.

◆ clearBusy()

void Storage::clearBusy ( uint16_t  recordKey)
private

◆ continueFactoryReset()

cs_ret_code_t Storage::continueFactoryReset ( )
private

Continue the factory reset process.

Return values
ERR_SUCCESSSuccessfully started factory reset process.
ERR_BUSYBusy, restart the whole factory reset from the beginning.
otherOther errors.

◆ eraseAllPages()

cs_ret_code_t Storage::eraseAllPages ( )

Erase all flash pages used by FDS.

This should only be used to recover from a failing init.

Return values
ERR_SUCCESSWhen successfully started erasing all pages.
ERR_NOT_AVAILABLEWhen you can't use this function (storage initialized already).

◆ eraseNextPage()

void Storage::eraseNextPage ( )
private

Erase next page, started via eraseAllPages().

◆ erasePages()

cs_ret_code_t Storage::erasePages ( const CS_TYPE  doneEvent,
void *  startAddress,
void *  endAddress 
)

Erase flash pages.

Must be called before storage is initialized.

Parameters
[in]doneEventType of event that should be sent when pages have been erased.
[in]startAddressAddress of first page to erase.
[in]endAddressAddress of first page not to erase.
Return values
ERR_SUCCESSWhen successfully started erasing all pages.
ERR_NOT_AVAILABLEWhen you can't use this function (storage initialized already).

◆ exists()

ret_code_t Storage::exists ( cs_file_id_t  file_id,
uint16_t  recordKey,
fds_record_desc_t &  record_desc,
bool &  result 
)
private

Check if a type of record exists and return the record descriptor.

Parameters
[in]file_idFile id to search.
[in]recordKeyRecord key to search for.
[out]record_descRecord descriptor, used to manipulate records.
[out]resultTrue if record was found.

◆ factoryReset()

cs_ret_code_t Storage::factoryReset ( )

Perform factory reset.

Make sure to restart factory reset on any error callback.

Return values
ERR_WAIT_FOR_SUCCESSSuccessfully started removing a record.
ERR_SUCCESSAll records have been removed.
ERR_BUSYBusy, try again later.
otherOther errors, maybe retry again later?

◆ findFirst()

cs_ret_code_t Storage::findFirst ( CS_TYPE  type,
cs_state_id_t id 
)

Find first id of stored values of given type.

NOTE: you should complete or abort this findFirst() / findNext() before starting a new one.

Parameters
[in]typeType to search for.
[out]idID of the found value.
Return values
ERR_SUCCESSWhen successful.
ERR_NOT_FOUNDWhen the first id of this type was not found.
ERR_BUSYWhen busy, try again later.

◆ findNext()

cs_ret_code_t Storage::findNext ( CS_TYPE  type,
cs_state_id_t id 
)

Find next id of stored values of given type.

NOTE: must be called immediately after findFirst(), no other storage operations should be done in between.

Parameters
[in]typeType to search for.
[out]idID of the found value.
Return values
ERR_SUCCESSWhen successful.
ERR_NOT_FOUNDWhen the next id of this type was not found.
ERR_WRONG_STATEWhen not called after findFirst(), or another storage operation was done in between.
ERR_BUSYWhen busy, try again later.

◆ findNextInternal()

cs_ret_code_t Storage::findNextInternal ( uint16_t  recordKey,
uint16_t &  fileId 
)
private

Find next fileId for given recordKey.

◆ garbageCollect()

cs_ret_code_t Storage::garbageCollect ( )

Garbage collection reclaims the flash space that is occupied by records that have been deleted, or that failed to be completely written due to, for example, a power loss.

Return values
ERR_SUCCESSWhen successfully started garbage collection.
ERR_BUSYWhen busy, try again later.

◆ garbageCollectInternal()

ret_code_t Storage::garbageCollectInternal ( )
private

◆ getErrorCode()

cs_ret_code_t Storage::getErrorCode ( ret_code_t  code)
private

◆ getFileId()

uint16_t Storage::getFileId ( cs_state_id_t  valueId)
private

Get file id, given state value id.

◆ getInstance()

static Storage & Storage::getInstance ( )
inlinestatic

Returns the singleton instance of this class.

Returns
static instance of Storage class

◆ getPaddedSize()

size16_t Storage::getPaddedSize ( size16_t  size)
private

Returns size after padding for flash.

◆ getStateId()

cs_state_id_t Storage::getStateId ( uint16_t  fileId)
private

Get state value id, given file id.

◆ handleFileStorageEvent()

void Storage::handleFileStorageEvent ( fds_evt_t const *  p_fds_evt)

Handle FDS events.

◆ handleFlashOperationError()

void Storage::handleFlashOperationError ( )

Handle FDS SOC event NRF_EVT_FLASH_OPERATION_ERROR.

◆ handleFlashOperationSuccess()

void Storage::handleFlashOperationSuccess ( )

Handle FDS SOC event NRF_EVT_FLASH_OPERATION_SUCCESS.

◆ handleGarbageCollectionEvent()

void Storage::handleGarbageCollectionEvent ( fds_evt_t const *  p_fds_evt)
private

◆ handleRemoveFileEvent()

void Storage::handleRemoveFileEvent ( fds_evt_t const *  p_fds_evt)
private

◆ handleRemoveRecordEvent()

void Storage::handleRemoveRecordEvent ( fds_evt_t const *  p_fds_evt)
private

◆ handleWriteEvent()

void Storage::handleWriteEvent ( fds_evt_t const *  p_fds_evt)
private

◆ init()

cs_ret_code_t Storage::init ( )

◆ initSearch() [1/2]

void Storage::initSearch ( )
private

Start a new search.

Call before using _findToken

◆ initSearch() [2/2]

void Storage::initSearch ( CS_TYPE  type)
private

Start a new search, where the user wants to iterate over a certain type.

◆ isBusy() [1/2]

bool Storage::isBusy ( )

◆ isBusy() [2/2]

bool Storage::isBusy ( uint16_t  recordKey)
private

◆ isErasingPages()

bool Storage::isErasingPages ( )
private

◆ isInitialized()

bool Storage::isInitialized ( )
inline

◆ isValidFileId()

bool Storage::isValidFileId ( uint16_t  fileId)
private

◆ isValidRecordKey()

bool Storage::isValidRecordKey ( uint16_t  recordKey)
private

◆ operator=()

void Storage::operator= ( Storage const &  )
privatedelete

◆ read()

cs_ret_code_t Storage::read ( cs_state_data_t data)

Find and read stored value of given type and id.

In case of duplicates (values with same type and id), you will get the latest value.

Parameters
[in,out]dataData struct with type and id to read. Pointer and size will be set afterwards.
Return values
ERR_SUCCESSWhen successful.
ERR_NOT_FOUNDWhen the type was not found.
ERR_WRONG_PAYLOAD_LENGTHWhen the given size does not match the stored size.
ERR_BUSYWhen busy, try again later.

◆ readFirst()

cs_ret_code_t Storage::readFirst ( cs_state_data_t data)

Find and read from first stored value of given type.

NOTE: you should complete or abort this readFirst() / readNext() before starting a new one.

Parameters
[in,out]dataData struct with type to read. ID, pointer, and size will be set afterwards.
Return values
ERR_SUCCESSWhen successful.
ERR_NOT_FOUNDWhen the type was not found.
ERR_WRONG_PAYLOAD_LENGTHWhen the given size does not match the stored size.
ERR_BUSYWhen busy, try again later.

◆ readNext()

cs_ret_code_t Storage::readNext ( cs_state_data_t data)

Find and read next stored value of given type.

NOTE: must be called immediately after readFirst(), no other storage operations should be done in between.

When iterating: just keep overwriting, so in case of duplicates (same type and id), you end up with the latest value.

Parameters
[in,out]dataData struct with type to read. ID, pointer, and size will be set afterwards.
Return values
ERR_SUCCESSWhen successful.
ERR_NOT_FOUNDWhen the type was not found.
ERR_WRONG_PAYLOAD_LENGTHWhen the given size does not match the stored size.
ERR_BUSYWhen busy, try again later.

◆ readNextInternal()

cs_ret_code_t Storage::readNextInternal ( uint16_t  recordKey,
uint16_t &  fileId,
uint8_t *  buf,
uint16_t  size 
)
private

Read next fileId for given recordKey.

◆ readRecord()

cs_ret_code_t Storage::readRecord ( fds_record_desc_t  recordDesc,
uint8_t *  buf,
uint16_t  size,
uint16_t &  fileId 
)
private

Read a record: copy data to buffer, and sets fileId.

Only returns success when data has been copied to buffer.

◆ readV3ResetCounter()

cs_ret_code_t Storage::readV3ResetCounter ( cs_state_data_t data)

Read the old (v3) reset counter.

Made to transfer reset counter from old location to new.

Parameters
[in,out]dataData struct with type and id to read. Pointer and size will be set afterwards.
Returns
Error code like read().

◆ remove() [1/3]

cs_ret_code_t Storage::remove ( cs_state_id_t  id)

Remove all values with given id.

Parameters
[in]idID of the values to remove.
Return values
ERR_SUCCESSWhen successfully started removing.
ERR_NOT_FOUNDWhen no match was not found, consider this a success, but don't wait for an event.
ERR_BUSYWhen busy, try again later.
ERR_NOT_INITIALIZEDWhen storage hasn't been initialized yet.

◆ remove() [2/3]

cs_ret_code_t Storage::remove ( CS_TYPE  type)

Remove all values of a type.

Parameters
[in]typeType to remove.
Return values
ERR_SUCCESSWhen successfully started removing the type.
ERR_NOT_FOUNDWhen no match was not found, consider this a success, but don't wait for an event.
ERR_BUSYWhen busy, try again later.
ERR_NOT_INITIALIZEDWhen storage hasn't been initialized yet.

◆ remove() [3/3]

cs_ret_code_t Storage::remove ( CS_TYPE  type,
cs_state_id_t  id 
)

Remove value of given type and id.

Parameters
[in]typeType to remove.
[in]idID of value to remove.
Return values
ERR_SUCCESSWhen successfully started removing the value.
ERR_NOT_FOUNDWhen no match was found, consider this a success, but don't wait for an event.
ERR_BUSYWhen busy, try again later.
ERR_NOT_INITIALIZEDWhen storage hasn't been initialized yet.

◆ setBusy()

void Storage::setBusy ( uint16_t  recordKey)
private

◆ setErrorCallback()

void Storage::setErrorCallback ( cs_storage_error_callback_t  callback)

Set the callback for errors.

These are errors like timeouts, that come in after a write/read/remove function returned.

Parameters
[in]callbackFunction to be called when an error occurred.

◆ write()

cs_ret_code_t Storage::write ( const cs_state_data_t data)

Write to persistent storage.

It is assumed that data pointer was allocated by this class.

Automatically starts garbage collection when needed.

Parameters
[in]dataData struct with type, data pointer, and size.
Return values
ERR_SUCCESSWhen successfully started to write.
ERR_BUSYWhen busy, try again later.
ERR_NO_SPACEWhen there is no space, not even after garbage collection.

◆ writeInternal()

ret_code_t Storage::writeInternal ( const cs_state_data_t data)
private

Write to persistent storage.

Friends And Related Function Documentation

◆ TestAccess< Storage >

friend class TestAccess< Storage >
friend

Member Data Documentation

◆ _busyRecordKeys

std::vector<uint16_t> Storage::_busyRecordKeys
private

◆ _collectingGarbage

bool Storage::_collectingGarbage = false
private

◆ _currentSearchType

CS_TYPE Storage::_currentSearchType = CS_TYPE::CONFIG_DO_NOT_USE
private

◆ _eraseDoneEvent

CS_TYPE Storage::_eraseDoneEvent = CS_TYPE::CONFIG_DO_NOT_USE
private

◆ _eraseEndPage

uint32_t Storage::_eraseEndPage = 0
private

Page that should not be erased.

Used by eraseAllPages().

◆ _erasePage

uint32_t Storage::_erasePage = 0
private

Next page to erase.

Used by eraseAllPages().

◆ _errorCallback

cs_storage_error_callback_t Storage::_errorCallback = NULL
private

◆ _findToken

fds_find_token_t Storage::_findToken
private

◆ _initialized

bool Storage::_initialized = false
private

◆ _performingFactoryReset

bool Storage::_performingFactoryReset = false
private

◆ _registeredFds

bool Storage::_registeredFds = false
private

◆ _removingFile

bool Storage::_removingFile = false
private

The documentation for this class was generated from the following file: