This commit is contained in:
moyuhai
2026-06-09 16:39:17 +08:00
commit 41a602f89c
3057 changed files with 771495 additions and 0 deletions
+199
View File
@@ -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_
+941
View File
@@ -0,0 +1,941 @@
/**
****************************************************************************************
*
* @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"
/*
* 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
}
/*
* 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