cleaned unused examples - 3
This commit is contained in:
@@ -0,0 +1,868 @@
|
||||
/**************************************************************************************************
|
||||
Filename: osal_snv.c
|
||||
Revised: $Date: 2013-02-15 10:12:26 -0800 (Fri, 15 Feb 2013) $
|
||||
Revision: $Revision: 33143 $
|
||||
|
||||
Description: This module contains the OSAL simple non-volatile memory functions.
|
||||
|
||||
|
||||
Copyright 2009-2013 Texas Instruments Incorporated. All rights reserved.
|
||||
|
||||
IMPORTANT: Your use of this Software is limited to those specific rights
|
||||
granted under the terms of a software license agreement between the user
|
||||
who downloaded the software, his/her employer (which must be your employer)
|
||||
and Texas Instruments Incorporated (the "License"). You may not use this
|
||||
Software unless you agree to abide by the terms of the License. The License
|
||||
limits your use, and you acknowledge, that the Software may not be modified,
|
||||
copied or distributed unless embedded on a Texas Instruments microcontroller
|
||||
or used solely and exclusively in conjunction with a Texas Instruments radio
|
||||
frequency transceiver, which is integrated into your product. Other than for
|
||||
the foregoing purpose, you may not use, reproduce, copy, prepare derivative
|
||||
works of, modify, distribute, perform, display or sell this Software and/or
|
||||
its documentation for any purpose.
|
||||
|
||||
YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
|
||||
PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
|
||||
NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
|
||||
TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
|
||||
NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
|
||||
LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
|
||||
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
|
||||
OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
|
||||
OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
|
||||
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
|
||||
|
||||
Should you have any questions regarding your right to use this Software,
|
||||
contact Texas Instruments Incorporated at www.TI.com.
|
||||
**************************************************************************************************/
|
||||
|
||||
/*********************************************************************
|
||||
* INCLUDES
|
||||
*/
|
||||
|
||||
#include "hal_adc.h"
|
||||
#include "hal_flash.h"
|
||||
#include "hal_types.h"
|
||||
#include "comdef.h"
|
||||
#include "OSAL.h"
|
||||
#include "osal_snv.h"
|
||||
#include "hal_assert.h"
|
||||
#include "saddr.h"
|
||||
|
||||
#ifdef OSAL_SNV_UINT16_ID
|
||||
# error "This OSAL SNV implementation does not support the extended ID space"
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* CONSTANTS
|
||||
*/
|
||||
|
||||
// NV page configuration
|
||||
#define OSAL_NV_PAGE_SIZE HAL_FLASH_PAGE_SIZE
|
||||
#define OSAL_NV_PAGES_USED HAL_NV_PAGE_CNT
|
||||
#define OSAL_NV_PAGE_BEG HAL_NV_PAGE_BEG
|
||||
#define OSAL_NV_PAGE_END (OSAL_NV_PAGE_BEG + OSAL_NV_PAGES_USED - 1)
|
||||
|
||||
// Default byte value when flash is erased
|
||||
#define OSAL_NV_ERASED 0xFF
|
||||
|
||||
// NV page header size in bytes
|
||||
#define OSAL_NV_PAGE_HDR_SIZE 4
|
||||
|
||||
// In case pages 0-1 are ever used, define a null page value.
|
||||
#define OSAL_NV_PAGE_NULL 0
|
||||
|
||||
// In case item Id 0 is ever used, define a null item value.
|
||||
#define OSAL_NV_ITEM_NULL 0
|
||||
|
||||
// Length in bytes of a flash word
|
||||
#define OSAL_NV_WORD_SIZE HAL_FLASH_WORD_SIZE
|
||||
|
||||
// NV page header offset within a page
|
||||
#define OSAL_NV_PAGE_HDR_OFFSET 0
|
||||
|
||||
|
||||
// Flag in a length field of an item header to indicate validity
|
||||
// of the length field
|
||||
#define OSAL_NV_INVALID_LEN_MARK 0x8000
|
||||
|
||||
// Flag in an ID field of an item header to indicate validity of
|
||||
// the identifier field
|
||||
#define OSAL_NV_INVALID_ID_MARK 0x8000
|
||||
|
||||
|
||||
// Bit difference between active page state indicator value and
|
||||
// transfer page state indicator value
|
||||
#define OSAL_NV_ACTIVE_XFER_DIFF 0x00100000
|
||||
|
||||
// active page state indicator value
|
||||
#define OSAL_NV_ACTIVE_PAGE_STATE OSAL_NV_ACTIVE_XFER_DIFF
|
||||
|
||||
// transfer page state indicator value
|
||||
#define OSAL_NV_XFER_PAGE_STATE (OSAL_NV_ACTIVE_PAGE_STATE ^ OSAL_NV_ACTIVE_XFER_DIFF)
|
||||
|
||||
#define OSAL_NV_MIN_COMPACT_THRESHOLD 70 // Minimum compaction threshold
|
||||
#define OSAL_NV_MAX_COMPACT_THRESHOLD 95 // Maximum compaction threshold
|
||||
|
||||
/*********************************************************************
|
||||
* MACROS
|
||||
*/
|
||||
|
||||
// Macro to check supply voltage
|
||||
#if (defined HAL_MCU_CC2530 || defined HAL_MCU_CC2531)
|
||||
# define OSAL_NV_CHECK_BUS_VOLTAGE (HalAdcCheckVdd(VDD_MIN_FLASH))
|
||||
#elif defined HAL_MCU_CC2533
|
||||
# define OSAL_NV_CHECK_BUS_VOLTAGE (HalBatMonRead( HAL_BATMON_MIN_FLASH ))
|
||||
#else
|
||||
// The radio chip does not support voltage monitoring
|
||||
# define OSAL_NV_CHECK_BUS_VOLTAGE TRUE
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* TYPEDEFS
|
||||
*/
|
||||
|
||||
// NV item header structure
|
||||
typedef struct
|
||||
{
|
||||
uint16 id;
|
||||
uint16 len;
|
||||
} osalNvItemHdr_t;
|
||||
// Note that osalSnvId_t and osalSnvLen_t cannot be bigger than uint16
|
||||
|
||||
/*********************************************************************
|
||||
* EXTERNAL FUNCTIONS
|
||||
*/
|
||||
|
||||
extern bool HalAdcCheckVdd(uint8 limit);
|
||||
|
||||
/*********************************************************************
|
||||
* GLOBAL VARIABLES
|
||||
*/
|
||||
|
||||
#ifndef OAD_KEEP_NV_PAGES
|
||||
// When NV pages are to remain intact during OAD download,
|
||||
// the image itself should not include NV pages.
|
||||
#pragma location="BLENV_ADDRESS_SPACE"
|
||||
__no_init uint8 _nvBuf[OSAL_NV_PAGES_USED * OSAL_NV_PAGE_SIZE];
|
||||
#pragma required=_nvBuf
|
||||
#endif // OAD_KEEP_NV_PAGES
|
||||
|
||||
#if defined MAKE_CRC_SHDW
|
||||
#pragma location="CRC_SHDW"
|
||||
const CODE uint16 _crcShdw = 0xFFFF;
|
||||
#pragma required=_crcShdw
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* LOCAL VARIABLES
|
||||
*/
|
||||
|
||||
// active page
|
||||
static uint8 activePg;
|
||||
|
||||
// active page offset
|
||||
static uint16 pgOff;
|
||||
|
||||
// flag to indicate that an error has occurred while writing to or erasing the
|
||||
// flash device. Once this flag indicates failure, it is unsafe to attempt
|
||||
// another write or erase.
|
||||
static uint8 failF;
|
||||
|
||||
/*********************************************************************
|
||||
* LOCAL FUNCTIONS
|
||||
*/
|
||||
|
||||
static uint8 initNV( void );
|
||||
|
||||
static void setActivePage( uint8 pg );
|
||||
static void setXferPage(void);
|
||||
static void erasePage( uint8 pg );
|
||||
static void cleanErasedPage( uint8 pg );
|
||||
static void findOffset( void );
|
||||
static void compactPage( uint8 pg );
|
||||
|
||||
static void writeWord( uint8 pg, uint16 offset, uint8 *pBuf );
|
||||
static void writeWordM( uint8 pg, uint16 offset, uint8 *pBuf, osalSnvLen_t cnt );
|
||||
|
||||
|
||||
// NOTE: Triggering erase upon power up may cause fast aging of the flash device
|
||||
// if there is power switch debounce issue, etc.
|
||||
// Improvement of this is to add a certain delay upon power up before
|
||||
// osal_nv_init() is called.
|
||||
|
||||
/*********************************************************************
|
||||
* @fn initNV
|
||||
*
|
||||
* @brief Initialize the NV flash pages.
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return TRUE if initialization succeeds. FALSE, otherwise.
|
||||
*/
|
||||
static uint8 initNV( void )
|
||||
{
|
||||
uint32 pgHdr;
|
||||
uint8 xferPg = OSAL_NV_PAGE_NULL;
|
||||
uint8 pg;
|
||||
|
||||
failF = FALSE;
|
||||
activePg = OSAL_NV_PAGE_NULL;
|
||||
|
||||
// Pick active page and clean up erased page if necessary
|
||||
for ( pg = OSAL_NV_PAGE_BEG; pg <= OSAL_NV_PAGE_END; pg++ )
|
||||
{
|
||||
HalFlashRead(pg, OSAL_NV_PAGE_HDR_OFFSET, (uint8 *)(&pgHdr), OSAL_NV_PAGE_HDR_SIZE);
|
||||
|
||||
if ( pgHdr == OSAL_NV_ACTIVE_PAGE_STATE)
|
||||
{
|
||||
if (activePg != OSAL_NV_PAGE_NULL)
|
||||
{
|
||||
// Both pages are active only when power failed during flash erase and
|
||||
// with very low probability.
|
||||
// As it is hard (code size intensive) to figure out which page is the real active page,
|
||||
// and theoretically impossible as well in lowest probability, erase both pages
|
||||
// in this case
|
||||
cleanErasedPage(activePg);
|
||||
cleanErasedPage(pg);
|
||||
activePg = OSAL_NV_PAGE_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
activePg = pg;
|
||||
}
|
||||
}
|
||||
else if ( pgHdr == OSAL_NV_XFER_PAGE_STATE)
|
||||
{
|
||||
xferPg = pg;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Erase this page if it is not erased.
|
||||
// This is to ensure that any page that were in the middle of
|
||||
// compacting gets erased.
|
||||
cleanErasedPage(pg);
|
||||
}
|
||||
}
|
||||
|
||||
if (activePg == OSAL_NV_PAGE_NULL)
|
||||
{
|
||||
if (xferPg == OSAL_NV_PAGE_NULL)
|
||||
{
|
||||
// Both pages are erased. This must be initial state.
|
||||
// Pick one page as active page.
|
||||
setActivePage(OSAL_NV_PAGE_BEG);
|
||||
pgOff = OSAL_NV_PAGE_HDR_SIZE;
|
||||
|
||||
// If setting active page from a completely erased page failed,
|
||||
// it is not recommended to operate any further.
|
||||
// Other cases, even if non-active page is corrupt, NV module can still read
|
||||
// the active page content and hence this function could return TRUE.
|
||||
return (!failF);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compacting a page hasn't completed in previous power cycle.
|
||||
// Complete the compacting.
|
||||
activePg = xferPg;
|
||||
findOffset();
|
||||
|
||||
compactPage(xferPg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (xferPg != OSAL_NV_PAGE_NULL)
|
||||
{
|
||||
// Compacting has completed except for the final step of erasing
|
||||
// the xferPage.
|
||||
erasePage(xferPg);
|
||||
}
|
||||
|
||||
// find the active page offset to write a new variable location item
|
||||
findOffset();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn setActivePage
|
||||
*
|
||||
* @brief Set page header active state to be active.
|
||||
*
|
||||
* @param pg - Valid NV page to activate.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void setActivePage( uint8 pg )
|
||||
{
|
||||
uint32 pgHdr;
|
||||
|
||||
pgHdr = OSAL_NV_ACTIVE_PAGE_STATE;
|
||||
|
||||
writeWord( pg, OSAL_NV_PAGE_HDR_OFFSET, (uint8*) &pgHdr );
|
||||
if (!failF)
|
||||
{
|
||||
activePg = pg;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn setXferPage
|
||||
*
|
||||
* @brief Set active page header state to be transfer state.
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void setXferPage(void)
|
||||
{
|
||||
uint32 pgHdr;
|
||||
|
||||
// erase difference bit between active state and xfer state
|
||||
pgHdr = OSAL_NV_XFER_PAGE_STATE;
|
||||
|
||||
writeWord( activePg, OSAL_NV_PAGE_HDR_OFFSET, (uint8*)&pgHdr );
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn erasePage
|
||||
*
|
||||
* @brief Erases a page in Flash.
|
||||
*
|
||||
* @param pg - Valid NV page to erase.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void erasePage( uint8 pg )
|
||||
{
|
||||
if ( !OSAL_NV_CHECK_BUS_VOLTAGE || failF)
|
||||
{
|
||||
failF = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
HalFlashErase(pg);
|
||||
|
||||
{
|
||||
// Verify the erase operation
|
||||
uint16 offset;
|
||||
uint8 tmp;
|
||||
|
||||
for (offset = 0; offset < OSAL_NV_PAGE_SIZE; offset ++)
|
||||
{
|
||||
HalFlashRead(pg, offset, &tmp, 1);
|
||||
if (tmp != OSAL_NV_ERASED)
|
||||
{
|
||||
failF = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn cleanErasedPage
|
||||
*
|
||||
* @brief Erases a page in Flash if the page is not completely erased.
|
||||
*
|
||||
* @param pg - Valid NV page to erase.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void cleanErasedPage( uint8 pg )
|
||||
{
|
||||
uint8 buf;
|
||||
uint16 offset;
|
||||
|
||||
for (offset = 0; offset < OSAL_NV_PAGE_SIZE; offset ++)
|
||||
{
|
||||
HalFlashRead(pg, offset, &buf, 1);
|
||||
if (buf != OSAL_NV_ERASED)
|
||||
{
|
||||
erasePage(pg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn findOffset
|
||||
*
|
||||
* @brief find an offset of an empty space in active page
|
||||
* where to write a new item to.
|
||||
*
|
||||
* @param None
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void findOffset(void)
|
||||
{
|
||||
uint16 offset;
|
||||
for (offset = OSAL_NV_PAGE_SIZE - OSAL_NV_WORD_SIZE;
|
||||
offset >= OSAL_NV_PAGE_HDR_SIZE;
|
||||
offset -= OSAL_NV_WORD_SIZE)
|
||||
{
|
||||
uint32 tmp;
|
||||
|
||||
HalFlashRead(activePg, offset, (uint8 *)&tmp, OSAL_NV_WORD_SIZE);
|
||||
if (tmp != 0xFFFFFFFF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
pgOff = offset + OSAL_NV_WORD_SIZE;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn findItem
|
||||
*
|
||||
* @brief find a valid item from a designated page and offset
|
||||
*
|
||||
* @param pg - NV page
|
||||
* @param offset - offset in the NV page from where to start
|
||||
* search up.
|
||||
* Usually this paramter is set to the empty space
|
||||
* offset.
|
||||
* @param id - NV item ID to search for
|
||||
*
|
||||
* @return offset of the item, 0 when not found
|
||||
*/
|
||||
static uint16 findItem(uint8 pg, uint16 offset, osalSnvId_t id)
|
||||
{
|
||||
offset -= OSAL_NV_WORD_SIZE;
|
||||
|
||||
while (offset >= OSAL_NV_PAGE_HDR_SIZE)
|
||||
{
|
||||
osalNvItemHdr_t hdr;
|
||||
|
||||
HalFlashRead(pg, offset, (uint8 *) &hdr, OSAL_NV_WORD_SIZE);
|
||||
|
||||
if (hdr.id == id)
|
||||
{
|
||||
// item found
|
||||
// length field could be corrupt. Mask invalid length mark.
|
||||
uint8 len = hdr.len & ~OSAL_NV_INVALID_LEN_MARK;
|
||||
return offset - len;
|
||||
}
|
||||
else if (hdr.len & OSAL_NV_INVALID_LEN_MARK)
|
||||
{
|
||||
offset -= OSAL_NV_WORD_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// valid length field
|
||||
if (hdr.len + OSAL_NV_WORD_SIZE <= offset)
|
||||
{
|
||||
// valid length
|
||||
offset -= hdr.len + OSAL_NV_WORD_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// active page is corrupt
|
||||
// This could happen if NV initialization failed upon failure to erase
|
||||
// page and active page is set to uncleanly erased page.
|
||||
HAL_ASSERT_FORCED();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn writeItem
|
||||
*
|
||||
* @brief Write a data item to NV. Function can write an entire item to NV
|
||||
*
|
||||
* @param pg - Page number
|
||||
* @param offset - offset within the NV page where to write the new item
|
||||
* @param id - NV item ID
|
||||
* @param alignedLen - Length of data to write, alinged in flash word
|
||||
* boundary
|
||||
* @param *pBuf - Data to write.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void writeItem( uint8 pg, uint16 offset, osalSnvId_t id, uint16 alignedLen, uint8 *pBuf )
|
||||
{
|
||||
osalNvItemHdr_t hdr;
|
||||
|
||||
hdr.id = 0xFFFF;
|
||||
hdr.len = alignedLen | OSAL_NV_INVALID_LEN_MARK;
|
||||
|
||||
// Write the len portion of the header first
|
||||
writeWord(pg, offset + alignedLen, (uint8 *) &hdr);
|
||||
|
||||
// remove invalid len mark
|
||||
hdr.len &= ~OSAL_NV_INVALID_LEN_MARK;
|
||||
writeWord(pg, offset + alignedLen, (uint8 *) &hdr);
|
||||
|
||||
// Copy over the data
|
||||
writeWordM(pg, offset, pBuf, alignedLen / OSAL_NV_WORD_SIZE);
|
||||
|
||||
// value is valid. Write header except for the most significant bit.
|
||||
hdr.id = id | OSAL_NV_INVALID_ID_MARK;
|
||||
writeWord(pg, offset + alignedLen, (uint8 *) &hdr);
|
||||
|
||||
// write the most significant bit
|
||||
hdr.id &= ~OSAL_NV_INVALID_ID_MARK;
|
||||
writeWord(pg, offset + alignedLen, (uint8 *) &hdr);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn xferItem
|
||||
*
|
||||
* @brief Copy an NV item from the active page to a designated page.
|
||||
*
|
||||
* @param pg - NV page where to copy the item to.
|
||||
* @param offset - NV page offset where to copy the item to.
|
||||
* @param alignedLen - Length of data to write, aligned in flash word
|
||||
* boundary.
|
||||
* @param srcOff - NV page offset of the original data in active page
|
||||
*
|
||||
* @return none.
|
||||
*/
|
||||
static void xferItem( uint8 pg, uint16 offset, uint16 alignedLen, uint16 srcOff )
|
||||
{
|
||||
uint8 tmp[OSAL_NV_WORD_SIZE];
|
||||
uint16 i = 0;
|
||||
|
||||
// Copy over the data
|
||||
while (i <= alignedLen)
|
||||
{
|
||||
HalFlashRead(activePg, srcOff + i, tmp, OSAL_NV_WORD_SIZE);
|
||||
writeWord(pg, offset + i, tmp);
|
||||
|
||||
i += OSAL_NV_WORD_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn compactPage
|
||||
*
|
||||
* @brief Compacts the page specified.
|
||||
*
|
||||
* @param srcPg - Valid NV page to compact from.
|
||||
* The page must have changed its state (header) to xfer state
|
||||
* prior to this function call. This function will not
|
||||
* modify the state of its header to xfer state before starting
|
||||
* to compact.
|
||||
*
|
||||
* @return none.
|
||||
*/
|
||||
static void compactPage( uint8 srcPg )
|
||||
{
|
||||
uint16 srcOff, dstOff;
|
||||
uint8 dstPg;
|
||||
osalSnvId_t lastId = (osalSnvId_t) 0xFFFF;
|
||||
|
||||
dstPg = (srcPg == OSAL_NV_PAGE_BEG)? OSAL_NV_PAGE_END : OSAL_NV_PAGE_BEG;
|
||||
|
||||
dstOff = OSAL_NV_PAGE_HDR_SIZE;
|
||||
|
||||
// Read from the latest value
|
||||
srcOff = pgOff - sizeof(osalNvItemHdr_t);
|
||||
|
||||
while (srcOff >= OSAL_NV_PAGE_HDR_SIZE)
|
||||
{
|
||||
osalNvItemHdr_t hdr;
|
||||
|
||||
if (failF)
|
||||
{
|
||||
// Failure during transfer item will make next findItem error prone.
|
||||
return;
|
||||
}
|
||||
|
||||
HalFlashRead(srcPg, srcOff, (uint8 *) &hdr, OSAL_NV_WORD_SIZE);
|
||||
|
||||
if (hdr.id == 0xFFFF)
|
||||
{
|
||||
// Invalid entry. Skip this one.
|
||||
if (hdr.len & OSAL_NV_INVALID_LEN_MARK)
|
||||
{
|
||||
srcOff -= OSAL_NV_WORD_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hdr.len + OSAL_NV_WORD_SIZE <= srcOff)
|
||||
{
|
||||
srcOff -= hdr.len + OSAL_NV_WORD_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// invalid length. Source page must be a corrupt page.
|
||||
// This is possible only if the NV initialization failed upon erasing
|
||||
// what is selected as active page.
|
||||
// This is supposed to be a very rare case, as power should be
|
||||
// shutdown exactly during erase and then the page header is
|
||||
// still retained as either the Xfer or the Active state.
|
||||
|
||||
// For production code, it might be useful to attempt to erase the page
|
||||
// so that at next power cycle at least the device is runnable
|
||||
// (with all entries removed).
|
||||
// However, it might be still better not to attempt erasing the page
|
||||
// just to see if this very rare case actually happened.
|
||||
//erasePage(srcPg);
|
||||
|
||||
HAL_ASSERT_FORCED();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Consider only valid item
|
||||
if (!(hdr.id & OSAL_NV_INVALID_ID_MARK) && hdr.id != lastId)
|
||||
{
|
||||
// lastId is used to speed up compacting in case the same item ID
|
||||
// items were neighboring each other contiguously.
|
||||
lastId = (osalSnvId_t) hdr.id;
|
||||
|
||||
// Check if the latest value of the item was already written
|
||||
if (findItem(dstPg, dstOff, lastId) == 0)
|
||||
{
|
||||
// This item was not copied over yet.
|
||||
// This must be the latest value.
|
||||
// Write the latest value to the destination page
|
||||
|
||||
xferItem(dstPg, dstOff, hdr.len, srcOff - hdr.len);
|
||||
|
||||
dstOff += hdr.len + OSAL_NV_WORD_SIZE;
|
||||
}
|
||||
}
|
||||
srcOff -= hdr.len + OSAL_NV_WORD_SIZE;
|
||||
}
|
||||
|
||||
// All items copied.
|
||||
// Activate the new page
|
||||
setActivePage(dstPg);
|
||||
|
||||
if (!failF)
|
||||
{
|
||||
pgOff = dstOff; // update active page offset
|
||||
}
|
||||
|
||||
// Erase the currently active page
|
||||
erasePage(srcPg);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn verifyWordM
|
||||
*
|
||||
* @brief verify the written word.
|
||||
*
|
||||
* @param pg - A valid NV Flash page.
|
||||
* @param offset - A valid offset into the page.
|
||||
* @param pBuf - Pointer to source buffer.
|
||||
* @param cnt - Number of 4-byte blocks to verify.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void verifyWordM( uint8 pg, uint16 offset, uint8 *pBuf, osalSnvLen_t cnt )
|
||||
{
|
||||
uint8 tmp[OSAL_NV_WORD_SIZE];
|
||||
|
||||
while (cnt--)
|
||||
{
|
||||
// Reading byte per byte will reduce code size but will slow down
|
||||
// and not sure it will meet the timing requirements.
|
||||
HalFlashRead(pg, offset, tmp, OSAL_NV_WORD_SIZE);
|
||||
if (FALSE == osal_memcmp(tmp, pBuf, OSAL_NV_WORD_SIZE))
|
||||
{
|
||||
failF = TRUE;
|
||||
return;
|
||||
}
|
||||
offset += OSAL_NV_WORD_SIZE;
|
||||
pBuf += OSAL_NV_WORD_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn writeWord
|
||||
*
|
||||
* @brief Writes a Flash-WORD to NV.
|
||||
*
|
||||
* @param pg - A valid NV Flash page.
|
||||
* @param offset - A valid offset into the page.
|
||||
* @param pBuf - Pointer to source buffer.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void writeWord( uint8 pg, uint16 offset, uint8 *pBuf )
|
||||
{
|
||||
uint16 addr = (offset >> 2) + ((uint16)pg << 9);
|
||||
|
||||
if ( !failF )
|
||||
{
|
||||
HalFlashWrite(addr, pBuf, 1);
|
||||
verifyWordM(pg, offset, pBuf, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn writeWordM
|
||||
*
|
||||
* @brief Writes multiple Flash-WORDs to NV.
|
||||
*
|
||||
* @param pg - A valid NV Flash page.
|
||||
* @param offset - A valid offset into the page.
|
||||
* @param buf - Pointer to source buffer.
|
||||
* @param cnt - Number of 4-byte blocks to write.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void writeWordM( uint8 pg, uint16 offset, uint8 *buf, osalSnvLen_t cnt )
|
||||
{
|
||||
uint16 addr = (offset >> 2) + ((uint16)pg << 9);
|
||||
|
||||
if ( !failF )
|
||||
{
|
||||
HalFlashWrite(addr, buf, cnt);
|
||||
verifyWordM(pg, offset, buf, cnt);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn osal_snv_init
|
||||
*
|
||||
* @brief Initialize NV service.
|
||||
*
|
||||
* @return SUCCESS if initialization succeeds. FAILURE, otherwise.
|
||||
*/
|
||||
uint8 osal_snv_init( void )
|
||||
{
|
||||
if (!initNV())
|
||||
{
|
||||
// NV initialization failed
|
||||
HAL_ASSERT_FORCED();
|
||||
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn osal_snv_write
|
||||
*
|
||||
* @brief Write a data item to NV.
|
||||
*
|
||||
* @param id - Valid NV item Id.
|
||||
* @param len - Length of data to write.
|
||||
* @param *pBuf - Data to write.
|
||||
*
|
||||
* @return SUCCESS if successful, NV_OPER_FAILED if failed.
|
||||
*/
|
||||
uint8 osal_snv_write( osalSnvId_t id, osalSnvLen_t len, void *pBuf )
|
||||
{
|
||||
uint16 alignedLen;
|
||||
|
||||
{
|
||||
uint16 offset = findItem(activePg, pgOff, id);
|
||||
|
||||
if (offset > 0)
|
||||
{
|
||||
uint8 tmp;
|
||||
osalSnvLen_t i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
HalFlashRead(activePg, offset, &tmp, 1);
|
||||
if (tmp != ((uint8 *)pBuf)[i])
|
||||
{
|
||||
break;
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
|
||||
if (i == len)
|
||||
{
|
||||
// Changed value is the same value as before.
|
||||
// Return here instead of re-writing the same value to NV.
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alignedLen = ((len + OSAL_NV_WORD_SIZE - 1) / OSAL_NV_WORD_SIZE) * OSAL_NV_WORD_SIZE;
|
||||
|
||||
if ( pgOff + alignedLen + OSAL_NV_WORD_SIZE > OSAL_NV_PAGE_SIZE )
|
||||
{
|
||||
setXferPage();
|
||||
compactPage(activePg);
|
||||
}
|
||||
|
||||
// pBuf shall be referenced beyond its valid length to save code size.
|
||||
writeItem(activePg, pgOff, id, alignedLen, pBuf);
|
||||
if (failF)
|
||||
{
|
||||
return NV_OPER_FAILED;
|
||||
}
|
||||
|
||||
pgOff += alignedLen + OSAL_NV_WORD_SIZE;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn osal_snv_read
|
||||
*
|
||||
* @brief Read data from NV.
|
||||
*
|
||||
* @param id - Valid NV item Id.
|
||||
* @param len - Length of data to read.
|
||||
* @param *pBuf - Data is read into this buffer.
|
||||
*
|
||||
* @return SUCCESS if successful.
|
||||
* Otherwise, NV_OPER_FAILED for failure.
|
||||
*/
|
||||
uint8 osal_snv_read( osalSnvId_t id, osalSnvLen_t len, void *pBuf )
|
||||
{
|
||||
uint16 offset = findItem(activePg, pgOff, id);
|
||||
|
||||
if (offset != 0)
|
||||
{
|
||||
HalFlashRead(activePg, offset, pBuf, len);
|
||||
return SUCCESS;
|
||||
}
|
||||
return NV_OPER_FAILED;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn osal_snv_compact
|
||||
*
|
||||
* @brief Compacts NV if its usage has reached a specific threshold.
|
||||
*
|
||||
* @param threshold - compaction threshold
|
||||
*
|
||||
* @return SUCCESS if successful,
|
||||
* NV_OPER_FAILED if failed, or
|
||||
* INVALIDPARAMETER if threshold invalid.
|
||||
*/
|
||||
uint8 osal_snv_compact( uint8 threshold )
|
||||
{
|
||||
if ( ( threshold < OSAL_NV_MIN_COMPACT_THRESHOLD ) ||
|
||||
( threshold > OSAL_NV_MAX_COMPACT_THRESHOLD ) )
|
||||
{
|
||||
return INVALIDPARAMETER;
|
||||
}
|
||||
|
||||
// See if NV active page usage has reached compaction threshold
|
||||
if ( ( (uint32)pgOff * 100 ) >= ( OSAL_NV_PAGE_SIZE * (uint32)threshold ) )
|
||||
{
|
||||
setXferPage();
|
||||
compactPage(activePg);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
return NV_OPER_FAILED;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*********************************************************************/
|
||||
Reference in New Issue
Block a user