V1.0
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
****************************************************************************************
|
||||
*
|
||||
* @file nvds.h
|
||||
*
|
||||
* @brief Non Volatile Data Storage (NVDS) driver
|
||||
*
|
||||
* Copyright (C) RivieraWaves 2009-2015
|
||||
*
|
||||
****************************************************************************************
|
||||
*/
|
||||
#ifndef _NVDS_H_
|
||||
#define _NVDS_H_
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @addtogroup NVDS
|
||||
* @ingroup COMMON
|
||||
* @brief Non Volatile Data Storage (NVDS)
|
||||
*
|
||||
* Parameters management
|
||||
* there are two compilation options:
|
||||
* + NVDS_8BIT_TAGLENGTH :
|
||||
* if set, each TAG has a maximum length of 256 bytes
|
||||
* if not set, each TAG has a maximum length of 65536 bytes
|
||||
* + NVDS_PACKED :
|
||||
* if not set, all the TAG header structures and TAG data contents are stored with an
|
||||
* alignment on 32 bit boundary
|
||||
* if set, all the TAG header structures and TAG data contents are stored
|
||||
* consecutively without gaps (as would be a structure with pragma packed)
|
||||
* + NVDS_READ_WRITE :
|
||||
* if not set, only GET action on TAGs is provided.
|
||||
* if set, PUT/DEL/LOCK actions are provided in addition of GET action.
|
||||
*
|
||||
* @{
|
||||
****************************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
* INCLUDE FILES
|
||||
****************************************************************************************
|
||||
*/
|
||||
#include <stdbool.h> // boolean definition
|
||||
#include <stdint.h> // integer definition
|
||||
|
||||
|
||||
/*
|
||||
* DEFINES
|
||||
****************************************************************************************
|
||||
*/
|
||||
|
||||
/// NVDS is defined as read-write
|
||||
#define NVDS_READ_WRITE 1
|
||||
|
||||
/// NVDS is defined as packed
|
||||
#define NVDS_PACKED 1
|
||||
|
||||
/// NVDS has 8-bit length tags
|
||||
#define NVDS_8BIT_TAGLENGTH 1
|
||||
|
||||
#define FLASH_BASE (252*1024)
|
||||
#define FLASH_SECTOR_SIZE (4*1024)
|
||||
|
||||
/// Type of the tag length (8 or 16 bits)
|
||||
#if (NVDS_8BIT_TAGLENGTH)
|
||||
typedef uint8_t nvds_tag_len_t;
|
||||
#else
|
||||
typedef uint16_t nvds_tag_len_t;
|
||||
#endif // NVDS_8BIT_TAGLENGTH
|
||||
|
||||
|
||||
/*
|
||||
* ENUMERATION DEFINITIONS
|
||||
****************************************************************************************
|
||||
*/
|
||||
|
||||
/// Possible Returned Status
|
||||
enum NVDS_STATUS
|
||||
{
|
||||
/// NVDS status OK
|
||||
NVDS_OK,
|
||||
/// generic NVDS status KO
|
||||
NVDS_FAIL,
|
||||
/// NVDS TAG unrecognized
|
||||
NVDS_TAG_NOT_DEFINED,
|
||||
/// No space for NVDS
|
||||
NVDS_NO_SPACE_AVAILABLE,
|
||||
/// Length violation
|
||||
NVDS_LENGTH_OUT_OF_RANGE,
|
||||
/// NVDS parameter locked
|
||||
NVDS_PARAM_LOCKED,
|
||||
/// NVDS corrupted
|
||||
NVDS_CORRUPT
|
||||
};
|
||||
|
||||
/*
|
||||
* FUNCTION DECLARATIONS
|
||||
****************************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
* used init nvds flash base addr
|
||||
****************************************************************************************
|
||||
*/
|
||||
uint8_t nvds_space_init(uint32_t flash_size);
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Initialize NVDS.
|
||||
* @return NVDS_OK
|
||||
****************************************************************************************
|
||||
*/
|
||||
uint8_t nvds_init(uint32_t len);
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Look for a specific tag and return, if found and matching (in length), the
|
||||
* DATA part of the TAG.
|
||||
*
|
||||
* If the length does not match, the TAG header structure is still filled, in order for
|
||||
* the caller to be able to check the actual length of the TAG.
|
||||
*
|
||||
* @param[in] tag TAG to look for whose DATA is to be retrieved
|
||||
* @param[in] length Expected length of the TAG
|
||||
* @param[out] buf A pointer to the buffer allocated by the caller to be filled with
|
||||
* the DATA part of the TAG
|
||||
*
|
||||
* @return NVDS_OK The read operation was performed
|
||||
* NVDS_LENGTH_OUT_OF_RANGE The length passed in parameter is different than the TAG's
|
||||
****************************************************************************************
|
||||
*/
|
||||
uint8_t nvds_get(uint8_t tag, nvds_tag_len_t * lengthPtr, uint8_t *buf);
|
||||
|
||||
#if (NVDS_READ_WRITE == 1)
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Look for a specific tag and delete it (Status set to invalid)
|
||||
*
|
||||
* Implementation notes
|
||||
* 1. The write function call return status is not handled
|
||||
*
|
||||
* @param[in] tag TAG to mark as deleted
|
||||
*
|
||||
* @return NVDS_OK TAG found and deleted
|
||||
* NVDS_PARAM_LOCKED TAG found but can not be deleted because it is locked
|
||||
* (others) return values from function call @ref nvds_browse_tag
|
||||
****************************************************************************************
|
||||
*/
|
||||
uint8_t nvds_del(uint8_t tag);
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Look for a specific tag and lock it (Status lock bit set to LOCK).
|
||||
*
|
||||
* The write function call return status is not handled
|
||||
*
|
||||
* @param[in] tag TAG to mark as locked
|
||||
*
|
||||
* @return NVDS_OK TAG found and locked
|
||||
* (others) return values from function call @ref nvds_browse_tag
|
||||
****************************************************************************************
|
||||
*/
|
||||
uint8_t nvds_lock(uint8_t tag);
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief This function adds a specific TAG to the NVDS.
|
||||
*
|
||||
* Steps:
|
||||
* 1) parse all the TAGs to:
|
||||
* 1.1) calculate the total size of all the valid TAGs
|
||||
* 1.2) erase the existing TAGs that have the same ID
|
||||
* 1.3) check if we can use the same TAG area in case of an EEPROM
|
||||
* 1.4) check that the TAG is not locked
|
||||
* 2) if we have to add the new TAG at the end fo the NVDS (cant use same area):
|
||||
* 2.1) allocate the appropriate amount of memory
|
||||
* 2.2) purge the NVDS
|
||||
* 2.3) free the memory allocated
|
||||
* 2.4) check that there is now enough room for the new TAG or return
|
||||
* NO_SPACE_AVAILABLE
|
||||
* 3) add the new TAG
|
||||
*
|
||||
* @param[in] tag TAG to look for whose DATA is to be retrieved
|
||||
* @param[in] length Expected length of the TAG
|
||||
* @param[in] buf Pointer to the buffer containing the DATA part of the TAG to add to
|
||||
* the NVDS
|
||||
*
|
||||
* @return NVDS_OK New TAG correctly written to the NVDS
|
||||
* NVDS_PARAM_LOCKED New TAG is trying to overwrite a TAG that is locked
|
||||
* NO_SPACE_AVAILABLE New TAG can not fit in the available space in the NVDS
|
||||
****************************************************************************************
|
||||
*/
|
||||
uint8_t nvds_put(uint8_t tag, nvds_tag_len_t length, uint8_t *buf);
|
||||
|
||||
#endif //(NVDS_READ_WRITE == 1)
|
||||
|
||||
/// @} NVDS
|
||||
|
||||
#endif // _NVDS_H_
|
||||
@@ -0,0 +1,952 @@
|
||||
/**
|
||||
****************************************************************************************
|
||||
*
|
||||
* @file nvds.c
|
||||
*
|
||||
* @brief Non Volatile Data Storage (NVDS) driver
|
||||
*
|
||||
* Copyright (C) RivieraWaves 2009-2015
|
||||
*
|
||||
*
|
||||
****************************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @addtogroup NVDS
|
||||
* @{
|
||||
****************************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
* INCLUDE FILES
|
||||
****************************************************************************************
|
||||
*/
|
||||
#include "rwip_config.h" // RW SW configuration
|
||||
#if (NVDS_SUPPORT)
|
||||
|
||||
#include "arch.h" // main
|
||||
#include "co_math.h" // math operations
|
||||
#include "nvds.h" // nvds definitions
|
||||
#include <limits.h> // limits definitions
|
||||
#include <stddef.h> // standard definitions
|
||||
#include <string.h> // string definitions
|
||||
#if (USE_ROM_FLASH)
|
||||
#include "xc6xxx_fmc_spi.h"
|
||||
#endif // (USE_ROM_FLASH)
|
||||
|
||||
#define NVDS_RAM_SUPPORT defined(CFG_GAIA)
|
||||
#if (NVDS_RAM_SUPPORT)
|
||||
#include "mailbox.h"
|
||||
#endif // NVDS_RAM_SUPPORT
|
||||
#include "dbg.h"
|
||||
#include "xc_drv_fmc_spi.h"
|
||||
|
||||
/*
|
||||
* DEFINES
|
||||
****************************************************************************************
|
||||
*/
|
||||
|
||||
/// NVDS parameter data maximum length
|
||||
#if NVDS_8BIT_TAGLENGTH
|
||||
#define NVDS_PARAMETER_MAX_LENGTH UCHAR_MAX
|
||||
#else // NVDS_8BIT_TAGLENGTH
|
||||
#define NVDS_PARAMETER_MAX_LENGTH USHRT_MAX
|
||||
#endif // NVDS_8BIT_TAGLENGTH
|
||||
|
||||
/// TAG STATUS bit assignment
|
||||
#define NVDS_STATUS_VALID_MASK 0x01
|
||||
#define NVDS_STATUS_VALID 0x00
|
||||
#define NVDS_STATUS_NOT_VALID 0x01
|
||||
#define NVDS_STATUS_LOCKED_MASK 0x02
|
||||
#define NVDS_STATUS_LOCKED 0x00
|
||||
#define NVDS_STATUS_NOT_LOCKED 0x02
|
||||
#define NVDS_STATUS_ERASED_MASK 0x04
|
||||
#define NVDS_STATUS_ERASED 0x00
|
||||
#define NVDS_STATUS_NOT_ERASED 0x04
|
||||
|
||||
#if (NVDS_READ_WRITE == 1)
|
||||
/// Max storage for the NVDS device which can be used for tags
|
||||
#define NVDS_MAX_STORAGE_SIZE 0x0800 // 2KB
|
||||
#endif //(NVDS_READ_WRITE == 1)
|
||||
|
||||
// NVDS Mapping
|
||||
|
||||
/// Magic number offset
|
||||
#define NVDS_MAGIC_NUMBER_ADDRESS 0x0000
|
||||
/// Size of magic number
|
||||
#define NVDS_MAGIC_NUMBER_LENGTH 4
|
||||
|
||||
/// Start of NVDS data
|
||||
#if (NVDS_PACKED == 1)
|
||||
#define NVDS_START_STORAGE_AREA_ADDRESS \
|
||||
NVDS_MAGIC_NUMBER_ADDRESS + NVDS_MAGIC_NUMBER_LENGTH
|
||||
#else //(NVDS_PACKED == 0)
|
||||
#define NVDS_START_STORAGE_AREA_ADDRESS \
|
||||
CO_ALIGN4_HI(NVDS_MAGIC_NUMBER_ADDRESS) + \
|
||||
CO_ALIGN4_HI(NVDS_MAGIC_NUMBER_LENGTH)
|
||||
#endif //(NVDS_PACKED == 1)
|
||||
|
||||
/// Value found in flash when nothing has been written
|
||||
#define NVDS_NO_TAG 0xFF
|
||||
|
||||
/*
|
||||
* MACROS
|
||||
****************************************************************************************
|
||||
*/
|
||||
|
||||
/// Check is tag is the last one
|
||||
#define NVDS_IS_TAG_LAST(h) ((h).tag == NVDS_NO_TAG)
|
||||
/// Check is tag is valid
|
||||
#define NVDS_IS_TAG_OK(h) \
|
||||
((((h).status) & (NVDS_STATUS_VALID_MASK | NVDS_STATUS_ERASED_MASK)) == \
|
||||
(NVDS_STATUS_VALID | NVDS_STATUS_NOT_ERASED))
|
||||
/// Check is tag is locked
|
||||
#define NVDS_IS_TAG_LOCKED(h) \
|
||||
((((h).status) & NVDS_STATUS_LOCKED_MASK) == NVDS_STATUS_LOCKED)
|
||||
/// Set tag as erased
|
||||
#define NVDS_SET_TAG_ERASED(h) \
|
||||
((((h).status) & (~NVDS_STATUS_ERASED_MASK)) | NVDS_STATUS_ERASED)
|
||||
/// Set tag as locked
|
||||
#define NVDS_SET_TAG_LOCKED(h) \
|
||||
((((h).status) & (~NVDS_STATUS_LOCKED_MASK)) | NVDS_STATUS_LOCKED)
|
||||
/// Set tag as valid
|
||||
#define NVDS_SET_TAG_OK(h) \
|
||||
(NVDS_STATUS_VALID | NVDS_STATUS_NOT_LOCKED | NVDS_STATUS_NOT_ERASED)
|
||||
|
||||
/// Macro for alignment
|
||||
#if (NVDS_PACKED == 1)
|
||||
#define NVDS_ALIGNMENT(p) (p)
|
||||
#else //(NVDS_PACKED == 0)
|
||||
#define NVDS_ALIGNMENT(p) CO_ALIGN4_HI(p)
|
||||
#endif //(NVDS_PACKED == 1)
|
||||
|
||||
/// Length of tag header
|
||||
#define NVDS_TAG_HEADER_LENGTH NVDS_ALIGNMENT(sizeof(struct nvds_tag_header))
|
||||
/// Length of tag data
|
||||
#define NVDS_TAG_CONTENT_LENGTH(h) NVDS_ALIGNMENT((h).length)
|
||||
/// Full length of tag (header+data)
|
||||
#define NVDS_TAG_FULL_LENGTH(h) \
|
||||
NVDS_TAG_HEADER_LENGTH + NVDS_TAG_CONTENT_LENGTH(h)
|
||||
|
||||
/*
|
||||
* STRUCT DEFINITIONS
|
||||
****************************************************************************************
|
||||
*/
|
||||
|
||||
/// Structure defining the header of a TAG. It is very important that the TAG
|
||||
/// remains the first element of the structure because it defines the LAST TAG
|
||||
/// of the NVDS when set the oxFF.
|
||||
struct nvds_tag_header
|
||||
{
|
||||
/// current TAG identifier
|
||||
uint8_t tag;
|
||||
/// status of the TAG (erased, locked ...)
|
||||
uint8_t status;
|
||||
/// length of the TAG
|
||||
nvds_tag_len_t length;
|
||||
};
|
||||
|
||||
/// Environment structure of the NVDS module
|
||||
struct nvds_env_tag
|
||||
{
|
||||
/// Function to read the device Address being in the NVDS memory space
|
||||
void (*read)(uint32_t const address, uint32_t const length,
|
||||
uint8_t *const buf);
|
||||
/// Function to write the device Address being in the NVDS memory space
|
||||
void (*write)(uint32_t const address, uint32_t const length,
|
||||
uint8_t *const buf);
|
||||
/// Function to erase the entire NVDS memory space
|
||||
void (*erase)(uint32_t const address, uint32_t const length);
|
||||
|
||||
/// NVDS base pointer
|
||||
uint8_t *nvds_space;
|
||||
|
||||
/// Total size of the NVDS area
|
||||
uint32_t total_size;
|
||||
|
||||
/// Flash ID
|
||||
uint8_t flash_id;
|
||||
};
|
||||
|
||||
/*
|
||||
* GLOBAL VARIABLE DECLARATIONS
|
||||
****************************************************************************************
|
||||
*/
|
||||
|
||||
#if (NVDS_READ_WRITE == 1)
|
||||
/// temporary buffer used for purging
|
||||
__STATIC uint8_t *nvds_temp_buf;
|
||||
#endif //(NVDS_READ_WRITE == 1)
|
||||
|
||||
/// NVDS magic number keyword
|
||||
// __STATIC const uint8_t nvds_magic_number[NVDS_MAGIC_NUMBER_LENGTH] = {'N',
|
||||
// 'V', 'D', 'S'};
|
||||
__STATIC const uint8_t nvds_magic_number[NVDS_MAGIC_NUMBER_LENGTH] = {'N', 'V',
|
||||
'D', 'S'};
|
||||
|
||||
/// NVDS environment
|
||||
__STATIC struct nvds_env_tag nvds_env;
|
||||
|
||||
/*
|
||||
* LOCAL FUNCTION DECLARATION
|
||||
****************************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Check if the current NVDS has the correct magic number set.
|
||||
*
|
||||
* Implementation notes:we do not put an assert on the read access because we
|
||||
*could be in the situation of a dummy read (returns always NVDS_FAIL) and we
|
||||
*want to return correctly the FALSE.
|
||||
*
|
||||
* @return True if the NVDS has the Magic Number set, false otherwise.
|
||||
****************************************************************************************
|
||||
*/
|
||||
__STATIC bool nvds_is_magic_number_ok(void);
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Look for a specific TAG.
|
||||
*
|
||||
* If found, it returns the address and the header, otherwise the TAG address
|
||||
*returned points to a location where it is possible to store a new TAG. The TAG
|
||||
*is returned only if it is valid (not erased). This function is useful to find
|
||||
* a single valid TAG element or find the next available space for a new TAG.
|
||||
*
|
||||
* @param[in] tag TAG to look for
|
||||
* @param[out] nvds_tag_header_ptr Pointer to the TAG header structure allocated
|
||||
*by the caller to contain the searched TAG header
|
||||
* @param[out] tag_address_ptr Pointer to the NVDS address at which TAG was
|
||||
*found (returned) or if the TAG was not found, first address free for storing
|
||||
*new TAG in NVDS
|
||||
*
|
||||
* @return Return codes from the @ref nvds_walk_tag function call
|
||||
****************************************************************************************
|
||||
*/
|
||||
__STATIC uint8_t nvds_browse_tag(uint8_t tag,
|
||||
struct nvds_tag_header *nvds_tag_header_ptr,
|
||||
uint32_t *tag_address_ptr);
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Read the TAG header that MUST be present at NVDS address cur_tag_addr
|
||||
*and fill the TAG header structure that is allocated by the caller and
|
||||
*referenced by nvds_tag_header_ptr.
|
||||
*
|
||||
* Upon completion of the read, the next TAG address is computed and returned to
|
||||
*the caller through nxt_tag_addr_ptr (except if the current TAG is the LAST
|
||||
*one). If the caller wishes to read the first TAG of the NVDS, the value
|
||||
* NVDS_START_STORAGE_AREA_ADDRESS can be used as the cur_tag_addr.
|
||||
* If the current Address specified is pointing at the position of the last
|
||||
*element of the NVDS the function returns NVDS_TAG_NOT_DEFINED. In this case,
|
||||
*there is NO VALUE returned through nxt_tag_addr_ptr. The cur_tag_addr is
|
||||
*already pointing to an empty TAG. The TAG read is not check for validity, this
|
||||
*information should be handled by the caller if he wishes to use the TAG
|
||||
*information correctly.
|
||||
*
|
||||
* @param[in] cur_tag_addr Address of the current TAG in NVDS memory
|
||||
*space
|
||||
* @param[out] nvds_tag_header_ptr A pointer to an allocated space for the
|
||||
*parameter header
|
||||
* @param[out] nxt_tag_addr_ptr A pointer to the next TAG address in the NVDS
|
||||
*memory space
|
||||
*
|
||||
* @return NVDS_OK TAG read, header filled and next TAG address
|
||||
*filled NVDS_TAG_NOT_DEFINED Last TAG reached, header filled with garbage
|
||||
* NVDS_CORRUPT Current TAG is overcoming the NVDS size
|
||||
*limit
|
||||
****************************************************************************************
|
||||
*/
|
||||
__STATIC uint8_t nvds_walk_tag(uint32_t cur_tag_addr,
|
||||
struct nvds_tag_header *nvds_tag_header_ptr,
|
||||
uint32_t *nxt_tag_addr_ptr);
|
||||
|
||||
#if (NVDS_RAM_SUPPORT)
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Hook a RAM driver to the NVDS.
|
||||
* If NVDS media is stored in RAM,
|
||||
*
|
||||
* @return NVDS_OK
|
||||
****************************************************************************************
|
||||
*/
|
||||
__STATIC uint8_t nvds_ram_init(uint8_t *base, uint32_t len);
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief RAM Read function
|
||||
*
|
||||
* @param[in] address Start address of the data to read from NVDS
|
||||
* @param[in] length Length of the data to read from NVDS
|
||||
* @param[in] buf Pointer to the buffer containing the DATA to read from
|
||||
*the NVDS
|
||||
****************************************************************************************
|
||||
*/
|
||||
__STATIC void nvds_ram_read(uint32_t address, uint32_t length, uint8_t *buf);
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief RAM Write function
|
||||
*
|
||||
* @param[in] address NVDS address at which the write operation must be
|
||||
*performed
|
||||
* @param[in] length Length of the write operation to perform
|
||||
* @param[in] buf Pointer to a buffer containing the data to write
|
||||
****************************************************************************************
|
||||
*/
|
||||
__STATIC void nvds_ram_write(uint32_t address, uint32_t length, uint8_t *buf);
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief RAM Erase function
|
||||
* @param[in] address NVDS address at which the erase operation must be
|
||||
*performed
|
||||
* @param[in] length Length of the erase operation to perform
|
||||
****************************************************************************************
|
||||
*/
|
||||
__STATIC void nvds_ram_erase(uint32_t address, uint32_t length);
|
||||
|
||||
#else // !(NVDS_RAM_SUPPORT)
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Hook a dummy driver to the NVDS.
|
||||
* If no valid NVDS media was found, to avoid incorrect behavior a dummy driver
|
||||
*should be hooked to the NVDS.
|
||||
*
|
||||
* @return NVDS_OK
|
||||
****************************************************************************************
|
||||
*/
|
||||
#if (NVDS_READ_WRITE == 0)
|
||||
__STATIC uint8_t nvds_null_init(void);
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Dummy function to safely replace Read function
|
||||
*
|
||||
* @param[in] address Start address of the data to read from NVDS
|
||||
* @param[in] length Length of the data to read from NVDS
|
||||
* @param[in] buf Pointer to the buffer containing the DATA to read from
|
||||
*the NVDS
|
||||
****************************************************************************************
|
||||
*/
|
||||
__STATIC void nvds_null_read(uint32_t address, uint32_t length, uint8_t *buf);
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Dummy function to safely replace Write function
|
||||
*
|
||||
* @param[in] address NVDS address at which the write operation must be
|
||||
*performed
|
||||
* @param[in] length Length of the write operation to perform
|
||||
* @param[in] buf Pointer to a buffer containing the data to write
|
||||
****************************************************************************************
|
||||
*/
|
||||
__STATIC void nvds_null_write(uint32_t address, uint32_t length, uint8_t *buf);
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Dummy function to safely replace Erase function
|
||||
* @param[in] address NVDS address at which the erase operation must be
|
||||
*performed
|
||||
* @param[in] length Length of the erase operation to perform
|
||||
****************************************************************************************
|
||||
*/
|
||||
__STATIC void nvds_null_erase(uint32_t address, uint32_t length);
|
||||
#endif // (NVDS_READ_WRITE == 0)
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Read data from NVDS.
|
||||
*
|
||||
* @param[in] address Start address of the data to read from NVDS
|
||||
* @param[in] length Length of the data to read from NVDS
|
||||
* @param[in] buf Pointer to the buffer containing the DATA to read from
|
||||
*the NVDS
|
||||
****************************************************************************************
|
||||
*/
|
||||
__STATIC void nvds_read(uint32_t address, uint32_t length, uint8_t *buf);
|
||||
|
||||
#if (NVDS_READ_WRITE == 1)
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Write data into NVDS
|
||||
*
|
||||
* @param[in] address Start address of the data to write to NVDS
|
||||
* @param[in] length Length of the data to write to NVDS
|
||||
* @param[in] buf Pointer to the buffer containing the DATA to write to
|
||||
*the NVDS
|
||||
****************************************************************************************
|
||||
*/
|
||||
__STATIC void nvds_write(uint32_t address, uint32_t length, uint8_t *buf);
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Erase data in NVDS
|
||||
*
|
||||
* @param[in] address Start address of the data to read from NVDS
|
||||
* @param[in] length Length of the data to read from NVDS
|
||||
****************************************************************************************
|
||||
*/
|
||||
__STATIC void nvds_erase(uint32_t address, uint32_t length);
|
||||
#endif // (NVDS_READ_WRITE == 1)
|
||||
|
||||
#endif //!(NVDS_RAM_SUPPORT)
|
||||
|
||||
#if (NVDS_READ_WRITE == 1)
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Initialize the NVDS memory.
|
||||
*
|
||||
* This function clears the entire memory content and writes the MagicNumber
|
||||
****************************************************************************************
|
||||
*/
|
||||
__STATIC void nvds_init_memory(void);
|
||||
|
||||
/**
|
||||
****************************************************************************************
|
||||
* @brief Purge NVDS memory
|
||||
*
|
||||
* This function performs a read of all the valid TAGs of the NVDS, stores them
|
||||
*in the temporary buffer allocated by the caller, flushes the NVDS and then
|
||||
*rewrites all the valid TAGs.
|
||||
*
|
||||
* It is used to purge the NVDS when there is no more space to store a new TAG
|
||||
*for example or regularly to save TAG browse time.
|
||||
*
|
||||
* @param[in] length Length of the buffer allocated to perform the temporary
|
||||
*storage of the NVDS while purging (erase and compress)
|
||||
* @param[in] buf A pointer to the buffer allocated by the caller for the
|
||||
*temporary storage of the NVDS while purging
|
||||
****************************************************************************************
|
||||
*/
|
||||
__STATIC void nvds_purge(uint32_t length, uint8_t *buf);
|
||||
#endif //(NVDS_READ_WRITE == 1)
|
||||
|
||||
/*
|
||||
* LOCAL FUNCTION DEFINITIONS
|
||||
****************************************************************************************
|
||||
*/
|
||||
extern uint8_t *get_fota_env_addr(uint16_t len);
|
||||
|
||||
__STATIC bool nvds_is_magic_number_ok(void)
|
||||
{
|
||||
bool is_magic_number_ok = false;
|
||||
uint8_t read_magic_number[NVDS_MAGIC_NUMBER_LENGTH];
|
||||
|
||||
// Look for the magic number
|
||||
nvds_env.read(NVDS_MAGIC_NUMBER_ADDRESS, sizeof(read_magic_number),
|
||||
read_magic_number);
|
||||
|
||||
// Compare the read magic number with the correct value
|
||||
if (memcmp(read_magic_number, nvds_magic_number,
|
||||
NVDS_MAGIC_NUMBER_LENGTH) == 0) {
|
||||
is_magic_number_ok = true;
|
||||
}
|
||||
return is_magic_number_ok;
|
||||
}
|
||||
|
||||
__STATIC uint8_t nvds_walk_tag(uint32_t cur_tag_addr,
|
||||
struct nvds_tag_header *nvds_tag_header_ptr,
|
||||
uint32_t *nxt_tag_addr_ptr)
|
||||
{
|
||||
uint8_t status = NVDS_OK;
|
||||
|
||||
// Read the current parameter header
|
||||
nvds_env.read((uint32_t)cur_tag_addr,
|
||||
(uint32_t)sizeof(struct nvds_tag_header),
|
||||
(uint8_t *)nvds_tag_header_ptr);
|
||||
|
||||
// Check if the read operation completed successfully
|
||||
if (!NVDS_IS_TAG_LAST(*nvds_tag_header_ptr)) {
|
||||
// Calculate the address of the next tag
|
||||
*nxt_tag_addr_ptr =
|
||||
cur_tag_addr + NVDS_TAG_FULL_LENGTH(*nvds_tag_header_ptr);
|
||||
|
||||
// Check if there is enough space to read next header
|
||||
// the limit is set minus 1 because we need to leave at least an end
|
||||
// marker
|
||||
if (*nxt_tag_addr_ptr > (nvds_env.total_size - 1)) {
|
||||
// Going above NVDS limit, probably an error occurred
|
||||
ASSERT_ERR(0);
|
||||
status = NVDS_CORRUPT;
|
||||
}
|
||||
} else {
|
||||
// this is beyond the last TAG
|
||||
status = NVDS_TAG_NOT_DEFINED;
|
||||
}
|
||||
return (status);
|
||||
}
|
||||
|
||||
__STATIC uint8_t nvds_browse_tag(uint8_t tag,
|
||||
struct nvds_tag_header *nvds_tag_header_ptr,
|
||||
uint32_t *tag_address_ptr)
|
||||
{
|
||||
uint8_t status;
|
||||
uint32_t cur_tag_addr, nxt_tag_addr;
|
||||
|
||||
// set the address to the first data byte of the NVDS
|
||||
nxt_tag_addr = NVDS_START_STORAGE_AREA_ADDRESS;
|
||||
|
||||
do {
|
||||
// go to the next tag
|
||||
cur_tag_addr = nxt_tag_addr;
|
||||
|
||||
// retrieve the parameter header
|
||||
status =
|
||||
nvds_walk_tag(cur_tag_addr, nvds_tag_header_ptr, &nxt_tag_addr);
|
||||
|
||||
} while ((status == NVDS_OK) && !((nvds_tag_header_ptr->tag == tag) &&
|
||||
NVDS_IS_TAG_OK(*nvds_tag_header_ptr)));
|
||||
|
||||
// the returned address is the last address found
|
||||
*tag_address_ptr = cur_tag_addr;
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
#if (NVDS_RAM_SUPPORT)
|
||||
__STATIC void nvds_ram_read(uint32_t address, uint32_t length, uint8_t *buf)
|
||||
{
|
||||
// Test the validity of address + length
|
||||
ASSERT_ERR(((address + length) <= nvds_env.total_size));
|
||||
|
||||
// Read the RAM memory
|
||||
memcpy(buf, (void *)(nvds_env.nvds_space + address), length);
|
||||
}
|
||||
|
||||
#if (NVDS_READ_WRITE == 1)
|
||||
__STATIC void nvds_ram_write(uint32_t address, uint32_t length, uint8_t *buf)
|
||||
{
|
||||
// Test the validity of address + length
|
||||
ASSERT_ERR(((address + length) <= nvds_env.total_size));
|
||||
|
||||
// Write the RAM memory
|
||||
memcpy((void *)(nvds_env.nvds_space + address), buf, length);
|
||||
}
|
||||
|
||||
__STATIC void nvds_ram_erase(uint32_t address, uint32_t length)
|
||||
{
|
||||
uint8_t buf[4];
|
||||
uint32_t incr;
|
||||
|
||||
// Write 0 the RAM memory
|
||||
buf[0] = 255;
|
||||
buf[1] = 255;
|
||||
buf[2] = 255;
|
||||
buf[3] = 255;
|
||||
|
||||
for (incr = 0; incr < length; incr = incr + 4) {
|
||||
memcpy((void *)nvds_env.nvds_space + address + incr, buf, 4);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
__STATIC uint8_t nvds_ram_init(uint8_t *base, uint32_t len)
|
||||
{
|
||||
uint8_t status = NVDS_OK;
|
||||
|
||||
// Initialize the pointer to the NVDS
|
||||
nvds_env.nvds_space = base;
|
||||
|
||||
// initialize the access functions
|
||||
nvds_env.read = &nvds_ram_read;
|
||||
|
||||
#if (NVDS_READ_WRITE == 1)
|
||||
nvds_env.write = &nvds_ram_write;
|
||||
nvds_env.erase = &nvds_ram_erase;
|
||||
#else //(NVDS_READ_WRITE == 0)
|
||||
nvds_env.write = &nvds_null_write;
|
||||
nvds_env.erase = &nvds_null_erase;
|
||||
#endif //(NVDS_READ_WRITE == 1)
|
||||
|
||||
nvds_env.total_size = len;
|
||||
|
||||
// Check if NVDS is correctly initialized
|
||||
if (!nvds_is_magic_number_ok()) {
|
||||
#if (NVDS_READ_WRITE == 1)
|
||||
// Initialize the memory
|
||||
nvds_init_memory();
|
||||
#else //(NVDS_READ_WRITE == 0)
|
||||
// No NVDS, so select the NULL NVDS
|
||||
nvds_null_init();
|
||||
// Return bad status
|
||||
status = NVDS_FAIL;
|
||||
#endif //(NVDS_READ_WRITE == 1)
|
||||
}
|
||||
|
||||
return (status);
|
||||
}
|
||||
#else // !(NVDS_RAM_SUPPORT)
|
||||
|
||||
#if (NVDS_READ_WRITE == 0)
|
||||
__STATIC void nvds_null_read(uint32_t address, uint32_t length, uint8_t *buf) {}
|
||||
|
||||
__STATIC void nvds_null_write(uint32_t address, uint32_t length, uint8_t *buf)
|
||||
{
|
||||
}
|
||||
|
||||
__STATIC void nvds_null_erase(uint32_t address, uint32_t length) {}
|
||||
|
||||
__STATIC uint8_t nvds_null_init(void)
|
||||
{
|
||||
// init all the structure
|
||||
memset(&nvds_env, 0, sizeof(nvds_env));
|
||||
nvds_env.read = nvds_null_read;
|
||||
nvds_env.write = nvds_null_write;
|
||||
nvds_env.erase = nvds_null_erase;
|
||||
|
||||
return NVDS_OK;
|
||||
}
|
||||
#endif // (NVDS_READ_WRITE == 0)
|
||||
|
||||
__STATIC void nvds_read(uint32_t address, uint32_t length, uint8_t *buf)
|
||||
{
|
||||
// Test the validity of address + length
|
||||
ASSERT_ERR(((address + length) <= nvds_env.total_size));
|
||||
|
||||
// Read the memory
|
||||
#if (USE_XIP)
|
||||
GLOBAL_INT_DISABLE();
|
||||
FMC_SPI_FlashRead((uint32_t)nvds_env.nvds_space + address, buf, length);
|
||||
GLOBAL_INT_RESTORE();
|
||||
#endif // (USE_XIP)
|
||||
// rom_env.stack_printf("nvds_read address=%x length=%x\n", address,
|
||||
// length); DUMP_DATA_PRINTF(buf, length);
|
||||
}
|
||||
|
||||
#if (NVDS_READ_WRITE == 1)
|
||||
__STATIC void nvds_write(uint32_t address, uint32_t length, uint8_t *buf)
|
||||
{
|
||||
// Test the validity of address + length
|
||||
ASSERT_ERR(((address + length) <= nvds_env.total_size));
|
||||
|
||||
// Read the memory
|
||||
#if (USE_XIP)
|
||||
GLOBAL_INT_DISABLE();
|
||||
FMC_SPI_FlashWrite((uint32_t)nvds_env.nvds_space + address, buf, length);
|
||||
GLOBAL_INT_RESTORE();
|
||||
#endif // (USE_XIP)
|
||||
// rom_env.stack_printf("nvds_write address=%x length=%x\n", address,
|
||||
// length); DUMP_DATA_PRINTF(buf, length);
|
||||
}
|
||||
|
||||
__STATIC void nvds_erase(uint32_t address, uint32_t length)
|
||||
{
|
||||
|
||||
uint8_t sector_cnt = length / FLASH_SECTOR_SIZE;
|
||||
uint32_t erase_base = (uint32_t)nvds_env.nvds_space + address;
|
||||
uint32_t erase_address = 0;
|
||||
if (length % FLASH_SECTOR_SIZE) {
|
||||
sector_cnt = sector_cnt + 1;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < sector_cnt; i++) {
|
||||
// flash_erase(nvds_env.flash_id, (uint32_t)nvds_env.nvds_space +
|
||||
// address, length, NULL);
|
||||
erase_address = erase_base + i * FLASH_SECTOR_SIZE;
|
||||
#if (USE_XIP)
|
||||
GLOBAL_INT_DISABLE();
|
||||
FMC_SPI_Flash_Erase_Sector(erase_address);
|
||||
GLOBAL_INT_RESTORE();
|
||||
#endif // (USE_XIP)
|
||||
}
|
||||
}
|
||||
#endif // (NVDS_READ_WRITE == 1)
|
||||
|
||||
#endif // !(NVDS_RAM_SUPPORT)
|
||||
|
||||
#if (NVDS_READ_WRITE == 1)
|
||||
__STATIC void nvds_init_memory(void)
|
||||
{
|
||||
// clear the device
|
||||
nvds_env.erase((uint32_t)NVDS_MAGIC_NUMBER_ADDRESS, nvds_env.total_size);
|
||||
|
||||
// Write the magic number at address 0
|
||||
nvds_env.write((uint32_t)NVDS_MAGIC_NUMBER_ADDRESS,
|
||||
(uint32_t)NVDS_MAGIC_NUMBER_LENGTH,
|
||||
(uint8_t *)nvds_magic_number);
|
||||
}
|
||||
|
||||
__STATIC void nvds_purge(uint32_t length, uint8_t *buf)
|
||||
{
|
||||
uint8_t status;
|
||||
struct nvds_tag_header tag_hdr;
|
||||
uint32_t nxt_tag_addr;
|
||||
uint32_t total_length;
|
||||
uint8_t *walk_ptr;
|
||||
|
||||
// store all the valid TAG elements in the locally allocated buffer
|
||||
total_length = 0;
|
||||
nxt_tag_addr = NVDS_START_STORAGE_AREA_ADDRESS;
|
||||
walk_ptr = buf;
|
||||
do {
|
||||
// go to the next tag
|
||||
uint32_t cur_tag_addr = nxt_tag_addr;
|
||||
|
||||
status = nvds_walk_tag(cur_tag_addr, (struct nvds_tag_header *)&tag_hdr,
|
||||
&nxt_tag_addr);
|
||||
|
||||
if ((status == NVDS_OK) && NVDS_IS_TAG_OK(tag_hdr)) {
|
||||
// check that the current size is not overcoming the buffer
|
||||
total_length += NVDS_TAG_FULL_LENGTH(tag_hdr);
|
||||
ASSERT_ERR(total_length <= length);
|
||||
|
||||
// copy the header content
|
||||
*((struct nvds_tag_header *)walk_ptr) = tag_hdr;
|
||||
|
||||
// increment the pointer to the data part
|
||||
walk_ptr += NVDS_TAG_HEADER_LENGTH;
|
||||
cur_tag_addr += NVDS_TAG_HEADER_LENGTH;
|
||||
|
||||
// retrieve all the data part
|
||||
nvds_env.read((uint32_t)cur_tag_addr, (uint32_t)tag_hdr.length,
|
||||
walk_ptr);
|
||||
|
||||
// increment the walking pointer
|
||||
walk_ptr += NVDS_TAG_CONTENT_LENGTH(tag_hdr);
|
||||
}
|
||||
|
||||
} while (status == NVDS_OK);
|
||||
|
||||
// reinitialize the flash
|
||||
nvds_init_memory();
|
||||
|
||||
// rewrite the NVDS once cleaned
|
||||
nvds_env.write((uint32_t)NVDS_START_STORAGE_AREA_ADDRESS,
|
||||
(uint32_t)total_length, buf);
|
||||
}
|
||||
#endif //(NVDS_READ_WRITE == 1)
|
||||
|
||||
/*
|
||||
* used init nvds flash base addr
|
||||
****************************************************************************************
|
||||
*/
|
||||
uint8_t nvds_space_init(uint32_t flash_size)
|
||||
{
|
||||
//nvds_env.nvds_space = flash_size - FLASH_PAGE_SIZE * 4 * 6; // the last 6K
|
||||
|
||||
uint16_t flash_type;
|
||||
|
||||
flash_size_and_type_get(&flash_size, &flash_type);
|
||||
|
||||
if (flash_type == GD25WD40_512K_FLASH) {
|
||||
nvds_env.nvds_space = flash_size - FLASH_PAGE_SIZE * 4 * 6; // the last 6K
|
||||
} else {
|
||||
nvds_env.nvds_space = flash_size - FLASH_PAGE_SIZE * 4 * 2; // the last 2K
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* EXPORTED FUNCTION DEFINITIONS
|
||||
****************************************************************************************
|
||||
*/
|
||||
|
||||
uint8_t nvds_init(uint32_t len)
|
||||
{
|
||||
// LOGI("nvds_init base=%x len=%d\n", nvds_env.nvds_space, len);
|
||||
uint8_t status = NVDS_OK;
|
||||
|
||||
// Initialize the pointer to the NVDS
|
||||
// nvds_env.nvds_space = base;
|
||||
// initialize the access functions
|
||||
nvds_env.read = &nvds_read;
|
||||
nvds_env.write = &nvds_write;
|
||||
nvds_env.erase = &nvds_erase;
|
||||
nvds_env.total_size = len;
|
||||
nvds_temp_buf = get_fota_env_addr(2048);
|
||||
// Check if NVDS is correctly initialized
|
||||
if (!nvds_is_magic_number_ok()) {
|
||||
nvds_init_memory();
|
||||
}
|
||||
return (status);
|
||||
}
|
||||
|
||||
uint8_t nvds_get(uint8_t tag, nvds_tag_len_t *lengthPtr, uint8_t *buf)
|
||||
{
|
||||
uint8_t status;
|
||||
uint32_t tag_addr;
|
||||
struct nvds_tag_header tag_hdr;
|
||||
|
||||
// try to find the TAG in the NVDS
|
||||
status = nvds_browse_tag(tag, &tag_hdr, &tag_addr);
|
||||
|
||||
// if the TAG was found
|
||||
if (status == NVDS_OK) {
|
||||
// The parameter is valid, verify that buffer is large enough to store
|
||||
// it
|
||||
if (*lengthPtr < tag_hdr.length) {
|
||||
status = NVDS_LENGTH_OUT_OF_RANGE;
|
||||
} else // All is OK, proceed to the read operation
|
||||
{
|
||||
// Copy data to output buffer
|
||||
nvds_env.read((uint32_t)(tag_addr + NVDS_TAG_HEADER_LENGTH),
|
||||
(uint32_t)tag_hdr.length, buf);
|
||||
// Return tag address
|
||||
*lengthPtr = tag_hdr.length;
|
||||
}
|
||||
} else {
|
||||
// Nothing to return, set length to 0
|
||||
*lengthPtr = 0;
|
||||
}
|
||||
return (status);
|
||||
}
|
||||
|
||||
#if (NVDS_READ_WRITE == 1)
|
||||
|
||||
uint8_t nvds_del(uint8_t tag)
|
||||
{
|
||||
uint8_t status;
|
||||
struct nvds_tag_header tag_hdr;
|
||||
uint32_t tag_addr;
|
||||
uint8_t status_to_write;
|
||||
|
||||
// look for the TAG
|
||||
status = nvds_browse_tag(tag, &tag_hdr, &tag_addr);
|
||||
|
||||
// Verify whether the parameter is locked or not
|
||||
if ((status == NVDS_OK) && NVDS_IS_TAG_LOCKED(tag_hdr)) {
|
||||
status = NVDS_PARAM_LOCKED;
|
||||
}
|
||||
|
||||
// Proceed to the delete operation
|
||||
if (status == NVDS_OK) {
|
||||
// then we set parameter to erased
|
||||
status_to_write = NVDS_SET_TAG_ERASED(tag_hdr);
|
||||
nvds_env.write(
|
||||
(uint32_t)(tag_addr + offsetof(struct nvds_tag_header, status)),
|
||||
(uint32_t)sizeof(status_to_write), (uint8_t *)&status_to_write);
|
||||
|
||||
#if (NVDS_RAM_SUPPORT)
|
||||
mailbox_send(E_NVDS_SAVE_REQ, NULL, 0); // request NVDS saved
|
||||
#endif //(NVDS_RAM_SUPPORT)
|
||||
}
|
||||
return (status);
|
||||
}
|
||||
|
||||
uint8_t nvds_lock(uint8_t tag)
|
||||
{
|
||||
uint8_t status;
|
||||
struct nvds_tag_header tag_hdr;
|
||||
uint32_t tag_addr;
|
||||
uint8_t status_to_write;
|
||||
|
||||
// look for the TAG
|
||||
status = nvds_browse_tag(tag, &tag_hdr, &tag_addr);
|
||||
|
||||
// Proceed to the lock operation
|
||||
if (status == NVDS_OK) {
|
||||
// The tag has been found, set the parameter to locked
|
||||
status_to_write = NVDS_SET_TAG_LOCKED(tag_hdr);
|
||||
nvds_env.write(
|
||||
(uint32_t)(tag_addr + offsetof(struct nvds_tag_header, status)),
|
||||
(uint32_t)sizeof(status_to_write), &status_to_write);
|
||||
}
|
||||
return (status);
|
||||
}
|
||||
|
||||
uint8_t nvds_put(uint8_t tag, nvds_tag_len_t length, uint8_t *buf)
|
||||
{
|
||||
uint8_t status;
|
||||
struct nvds_tag_header tag_hdr;
|
||||
uint8_t tag_buffer[NVDS_PARAMETER_MAX_LENGTH];
|
||||
uint32_t cur_tag_addr, nxt_tag_addr;
|
||||
uint8_t status_to_write;
|
||||
uint32_t total_length;
|
||||
|
||||
/* parse once all the TAG elements of the NVDS to:
|
||||
* 1) find same tag
|
||||
* 2) erase and invalidate the former tag
|
||||
* 3) compute the total length needed by the all valid tags
|
||||
* 4) retrieve the first address where new data can be stored */
|
||||
total_length = 0;
|
||||
nxt_tag_addr = NVDS_START_STORAGE_AREA_ADDRESS;
|
||||
do {
|
||||
// Go to the next tag
|
||||
cur_tag_addr = nxt_tag_addr;
|
||||
|
||||
// Read the next TAG header structure
|
||||
status = nvds_walk_tag(cur_tag_addr, &tag_hdr, &nxt_tag_addr);
|
||||
|
||||
// check TAG is valid
|
||||
if ((status == NVDS_OK) && NVDS_IS_TAG_OK(tag_hdr)) {
|
||||
// check TAG is identical to the new one
|
||||
if (tag_hdr.tag == tag) {
|
||||
// check TAG is not locked
|
||||
if (NVDS_IS_TAG_LOCKED(tag_hdr)) {
|
||||
return NVDS_PARAM_LOCKED;
|
||||
}
|
||||
|
||||
// Read parameter data
|
||||
nvds_env.read((uint32_t)(cur_tag_addr + NVDS_TAG_HEADER_LENGTH),
|
||||
(uint32_t)tag_hdr.length, tag_buffer);
|
||||
|
||||
// Compare data with new parameter
|
||||
if ((tag_hdr.length == length) &&
|
||||
!memcmp(buf, tag_buffer, tag_hdr.length)) {
|
||||
return NVDS_OK;
|
||||
}
|
||||
|
||||
// then we set parameter to erased
|
||||
status_to_write = NVDS_SET_TAG_ERASED(tag_hdr);
|
||||
nvds_env.write(
|
||||
(uint32_t)(cur_tag_addr +
|
||||
offsetof(struct nvds_tag_header, status)),
|
||||
(uint32_t)sizeof(status_to_write),
|
||||
(uint8_t *)&status_to_write);
|
||||
} else {
|
||||
// add the current tag length to the total length (used for
|
||||
// purge)
|
||||
total_length += NVDS_TAG_FULL_LENGTH(tag_hdr);
|
||||
}
|
||||
}
|
||||
} while (status == NVDS_OK);
|
||||
|
||||
// check that we've reached the last TAG of the NVDS
|
||||
if (status != NVDS_OK) {
|
||||
/* check if there is enough space to write next tag
|
||||
the limit is calculated including 2 TAG headers (the current and the
|
||||
next that is used to leave at least an end marker) */
|
||||
if ((cur_tag_addr + (NVDS_TAG_HEADER_LENGTH * 2) +
|
||||
NVDS_ALIGNMENT(length)) > (nvds_env.total_size)) {
|
||||
ASSERT_ERR(nvds_temp_buf != NULL);
|
||||
|
||||
// purge the NVDS using the current buffer
|
||||
nvds_purge(total_length, nvds_temp_buf);
|
||||
|
||||
// compute the next tag address in the NVDS memory space
|
||||
cur_tag_addr =
|
||||
NVDS_START_STORAGE_AREA_ADDRESS + NVDS_ALIGNMENT(total_length);
|
||||
|
||||
// if there is still not enough space, return an error
|
||||
if ((cur_tag_addr + NVDS_TAG_HEADER_LENGTH +
|
||||
NVDS_ALIGNMENT(length)) > (nvds_env.total_size - 1)) {
|
||||
return NVDS_NO_SPACE_AVAILABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First of all, write the data of the parameter
|
||||
nvds_env.write((uint32_t)(cur_tag_addr + NVDS_TAG_HEADER_LENGTH),
|
||||
(uint32_t)length, buf);
|
||||
|
||||
// Second of all, configure the new value of the TAG HEADER
|
||||
tag_hdr.tag = tag;
|
||||
tag_hdr.status = NVDS_SET_TAG_OK(tag_hdr);
|
||||
tag_hdr.length = length;
|
||||
|
||||
// Third of all, write the new TAG HEADER
|
||||
nvds_env.write((uint32_t)(cur_tag_addr), (uint32_t)sizeof(tag_hdr),
|
||||
(uint8_t *)&tag_hdr);
|
||||
|
||||
#if (NVDS_RAM_SUPPORT)
|
||||
mailbox_send(E_NVDS_SAVE_REQ, NULL, 0); // request NVDS saved
|
||||
#endif //(NVDS_RAM_SUPPORT)
|
||||
|
||||
return (NVDS_OK);
|
||||
}
|
||||
#endif // NVDS_RAM_SUPPORT
|
||||
|
||||
#endif //(NVDS_SUPPORT)
|
||||
|
||||
/// @} NVDS
|
||||
Reference in New Issue
Block a user