📄 osal_nv.c
字号:
tmp[0] = buf[0];
tmp[1] = buf[1];
tmp[2] = OSAL_NV_ERASED;
tmp[3] = OSAL_NV_ERASED;
writeWord( pg, offset, tmp );
}
/*********************************************************************
* @fn writeBuf
*
* @brief Writes a data buffer to NV.
*
* @param dstPg - A valid NV Flash page.
* @param offset - A valid offset into the page.
* @param len - Byte count of the data to write.
* @param buf - The data to write.
*
* @return TRUE if data buf checksum matches read back checksum, else FALSE.
*/
static void writeBuf( uint8 dstPg, uint16 dstOff, uint16 len, uint8 *buf )
{
uint32 addr;
uint8 idx, rem, tmp[OSAL_NV_WORD_SIZE];
rem = dstOff % OSAL_NV_WORD_SIZE;
if ( rem )
{
dstOff -= rem;
addr = OSAL_NV_PAGE_TO_ADDR( dstPg ) + dstOff;
for ( idx = 0; idx < rem; idx++ )
{
tmp[idx] = GetCodeByte( addr++ );
}
while ( (idx < OSAL_NV_WORD_SIZE) && len )
{
tmp[idx++] = *buf++;
len--;
}
while ( idx < OSAL_NV_WORD_SIZE )
{
tmp[idx++] = OSAL_NV_ERASED;
}
writeWord( dstPg, dstOff, tmp );
dstOff += OSAL_NV_WORD_SIZE;
}
rem = len % OSAL_NV_WORD_SIZE;
len /= OSAL_NV_WORD_SIZE;
while ( len-- )
{
writeWord( dstPg, dstOff, buf );
dstOff += OSAL_NV_WORD_SIZE;
buf += OSAL_NV_WORD_SIZE;
}
if ( rem )
{
for ( idx = 0; idx < rem; idx++ )
{
tmp[idx] = *buf++;
}
while ( idx < OSAL_NV_WORD_SIZE )
{
tmp[idx++] = OSAL_NV_ERASED;
}
writeWord( dstPg, dstOff, tmp );
}
}
/*********************************************************************
* @fn xferBuf
*
* @brief Xfers an NV buffer from one location to another, enforcing OSAL_NV_WORD_SIZE writes.
*
* @return none
*/
static void xferBuf( uint8 srcPg, uint16 srcOff, uint8 dstPg, uint16 dstOff, uint16 len )
{
uint32 addr;
uint8 idx, rem, tmp[OSAL_NV_WORD_SIZE];
rem = dstOff % OSAL_NV_WORD_SIZE;
if ( rem )
{
dstOff -= rem;
addr = OSAL_NV_PAGE_TO_ADDR( dstPg ) + dstOff;
for ( idx = 0; idx < rem; idx++ )
{
tmp[idx] = GetCodeByte( addr++ );
}
addr = OSAL_NV_PAGE_TO_ADDR( srcPg ) + srcOff;
while ( (idx < OSAL_NV_WORD_SIZE) && len )
{
tmp[idx++] = GetCodeByte( addr++ );
srcOff++;
len--;
}
while ( idx < OSAL_NV_WORD_SIZE )
{
tmp[idx++] = OSAL_NV_ERASED;
}
writeWord( dstPg, dstOff, tmp );
dstOff += OSAL_NV_WORD_SIZE;
}
rem = len % OSAL_NV_WORD_SIZE;
len = len / OSAL_NV_WORD_SIZE;
while ( len-- )
{
readWord( srcPg, srcOff, tmp );
srcOff += OSAL_NV_WORD_SIZE;
writeWord( dstPg, dstOff, tmp );
dstOff += OSAL_NV_WORD_SIZE;
}
if ( rem )
{
addr = OSAL_NV_PAGE_TO_ADDR( srcPg ) + srcOff;
for ( idx = 0; idx < rem; idx++ )
{
tmp[idx] = GetCodeByte( addr++ );
}
while ( idx < OSAL_NV_WORD_SIZE )
{
tmp[idx++] = OSAL_NV_ERASED;
}
writeWord( dstPg, dstOff, tmp );
}
}
/*********************************************************************
* @fn writeItem
*
* @brief Writes an item header/data combo to the specified NV page.
*
* @param pg - Valid NV Flash page.
* @param id - Valid NV item Id.
* @param len - Byte count of the data to write.
* @param buf - The data to write. If NULL, no data/checksum write.
*
* @return TRUE if header/data to write matches header/data read back, else FALSE.
*/
static uint8 writeItem( uint8 pg, uint16 id, uint16 len, void *buf )
{
uint16 offset = pgOff[pg-OSAL_NV_PAGE_BEG];
uint8 rtrn = FALSE;
osalNvHdr_t hdr;
uint16 sz;
if ( pg == pgRes )
{
/* Mark reserve page as being active, in process of receiving items.
* Invoking function must effect a page compaction.
*/
setPageUse( pg, FALSE );
}
hdr.id = id;
hdr.len = len;
writeWord( pg, offset, (uint8 *)&hdr );
readHdr( pg, offset, (uint8 *)(&hdr) );
if ( (hdr.id == id) && (hdr.len == len) )
{
if ( buf != NULL )
{
uint16 chk = calcChkB( len, buf );
offset += OSAL_NV_HDR_SIZE;
writeBuf( pg, offset, len, buf );
if ( chk == calcChkF( pg, offset, len ) )
{
writeWordH( pg, (offset-OSAL_NV_WORD_SIZE), (uint8 *)&chk );
readHdr( pg, (offset-OSAL_NV_HDR_SIZE), (uint8 *)(&hdr) );
if ( chk == hdr.chk )
{
rtrn = TRUE;
}
}
}
else
{
rtrn = TRUE;
}
}
sz = ((len + (OSAL_NV_WORD_SIZE-1)) / OSAL_NV_WORD_SIZE) * OSAL_NV_WORD_SIZE +
OSAL_NV_HDR_SIZE;
pgOff[pg-OSAL_NV_PAGE_BEG] += sz;
return rtrn;
}
/*********************************************************************
* @fn osal_nv_init
*
* @brief Initialize NV service.
*
* @param p - Not used.
*
* @return none
*/
void osal_nv_init( void *p )
{
(void)p; // Suppress Lint warning.
// Set Flash write timing based on CPU speed.
#ifdef CPU16MHZ
FWT = 0x15;
#else
FWT = 0x2A;
#endif
initDMA();
(void)initNV(); // Always returns TRUE after pages have been erased.
}
/*********************************************************************
* @fn osal_nv_item_init
*
* @brief If the NV item does not already exist, it is created and
* initialized with the data passed to the function, if any.
* This function must be called before calling osal_nv_read() or
* osal_nv_write().
*
* @param id - Valid NV item Id.
* @param len - Item length.
* @param *buf - Pointer to item initalization data. Set to NULL if none.
*
* @return NV_ITEM_UNINIT - Id did not exist and was created successfully.
* ZSUCCESS - Id already existed, no action taken.
* NV_OPER_FAILED - Failure to find or create Id.
*/
uint8 osal_nv_item_init( uint16 id, uint16 len, void *buf )
{
failF = FALSE;
/* ZCD_NV_EXTADDR is the only item maintained without an osalNvHdr_t,
* so it is always already initialized.
*/
if ( (id == ZCD_NV_EXTADDR) || (findItem( id ) != OSAL_NV_ITEM_NULL) )
{
return ZSUCCESS;
}
else if ( initItem( id, len, buf ) != OSAL_NV_PAGE_NULL )
{
if ( failF )
{
(void)initNV(); // See comment at the declaration of failF.
return NV_OPER_FAILED;
}
else
{
return NV_ITEM_UNINIT;
}
}
else
{
return NV_OPER_FAILED;
}
}
/*********************************************************************
* @fn osal_nv_item_len
*
* @brief Get the data length of the item stored in NV memory.
*
* @param id - Valid NV item Id.
*
* @return Item length, if found; zero otherwise.
*/
uint16 osal_nv_item_len( uint16 id )
{
if ( id == ZCD_NV_EXTADDR )
{
return Z_EXTADDR_LEN;
}
else
{
uint16 offset = findItem( id );
if ( offset == OSAL_NV_ITEM_NULL )
{
return 0;
}
else
{
osalNvHdr_t hdr;
readHdr( findPg, (offset - OSAL_NV_HDR_SIZE), (uint8 *)(&hdr) );
return hdr.len;
}
}
}
/*********************************************************************
* @fn osal_nv_write
*
* @brief Write a data item to NV. Function can write an entire item to NV or
* an element of an item by indexing into the item with an offset.
*
* @param id - Valid NV item Id.
* @param ndx - Index offset into item
* @param len - Length of data to write.
* @param *buf - Data to write.
*
* @return ZSUCCESS if successful, NV_ITEM_UNINIT if item did not
* exist in NV and offset is non-zero, NV_OPER_FAILED if failure.
*/
uint8 osal_nv_write( uint16 id, uint16 ndx, uint16 len, void *buf )
{
uint8 rtrn = ZSUCCESS;
/* Global fail flag for fail due to low bus voltage has less impact on code
* size than passing back a return value all the way from the lowest level.
*/
failF = FALSE;
if ( id == ZCD_NV_EXTADDR )
{
osalNvHdr_t hdr;
readHdr( OSAL_NV_IEEE_PAGE, OSAL_NV_IEEE_OFFSET, (uint8 *)(&hdr) );
if ( (hdr.id == OSAL_NV_ERASED_ID) &&
(hdr.len == OSAL_NV_ERASED_ID) &&
(hdr.chk == OSAL_NV_ERASED_ID) &&
(hdr.stat == OSAL_NV_ERASED_ID) )
{
writeWordD( OSAL_NV_IEEE_PAGE, OSAL_NV_IEEE_OFFSET, buf );
return ((failF) ? NV_OPER_FAILED : ZSUCCESS);
}
else
{
return NV_OPER_FAILED;
}
}
if ( len != 0 )
{
osalNvHdr_t hdr;
uint32 addr;
uint16 srcOff;
uint16 cnt;
uint8 *ptr;
srcOff = findItem( id );
if ( srcOff == OSAL_NV_ITEM_NULL )
{
return NV_ITEM_UNINIT;
}
readHdr( findPg, (srcOff - OSAL_NV_HDR_SIZE), (uint8 *)(&hdr) );
if ( hdr.len < (ndx + len) )
{
return NV_OPER_FAILED;
}
addr = OSAL_NV_PAGE_TO_ADDR( findPg ) + srcOff + ndx;
ptr = buf;
cnt = len;
do
{
if ( GetCodeByte( addr++ ) != *ptr++ )
{
break;
}
} while ( --cnt );
if ( cnt != 0 ) // If the buffer to write is different in one or more bytes.
{
uint8 comPg, srcPg;
comPg = srcPg = findPg;
// initItem2() can change the findPg and it advances pgOff[] of the dstPg.
uint8 dstPg = initItem2( id, hdr.len, &comPg );
if ( dstPg != OSAL_NV_PAGE_NULL )
{
uint16 tmp = ((hdr.len + (OSAL_NV_WORD_SIZE-1)) / OSAL_NV_WORD_SIZE) * OSAL_NV_WORD_SIZE;
uint16 dstOff = pgOff[dstPg-OSAL_NV_PAGE_BEG] - tmp;
uint16 origOff = srcOff;
setItem( srcPg, srcOff, eNvXfer );
xferBuf( srcPg, srcOff, dstPg, dstOff, ndx );
srcOff += ndx;
dstOff += ndx;
writeBuf( dstPg, dstOff, len, buf );
srcOff += len;
dstOff += len;
xferBuf( srcPg, srcOff, dstPg, dstOff, (hdr.len-ndx-len) );
// Calculate and write the new checksum.
dstOff = pgOff[dstPg-OSAL_NV_PAGE_BEG] - tmp;
tmp = calcChkF( dstPg, dstOff, hdr.len );
dstOff -= OSAL_NV_HDR_SIZE;
writeWordH( dstPg, (dstOff+OSAL_NV_HDR_CHK), (uint8 *)&tmp );
readHdr( dstPg, dstOff, (uint8 *)(&hdr) );
if ( tmp == hdr.chk )
{
setItem( srcPg, origOff, eNvZero );
}
else
{
rtrn = NV_OPER_FAILED;
}
if ( dstPg == pgRes )
{
compactPage( comPg );
}
}
else
{
rtrn = NV_OPER_FAILED;
}
}
}
if ( failF )
{
(void)initNV(); // See comment at the declaration of failF.
rtrn = NV_OPER_FAILED;
}
return rtrn;
}
/*********************************************************************
* @fn osal_nv_read
*
* @brief Read data from NV. This function can be used to read an
* entire item from NV or an element of an item by indexing
* into the item with an offset. Read data is copied into
* *buf.
*
* @param id - Valid NV item Id.
*
* @param ndx - Index offset into item
*
* @param len - Length of data to read.
*
* @param *buf - Data is read into this buffer.
*
* @return ZSUCCESS if NV data was copied to the parameter 'buf'.
* Otherwise, NV_OPER_FAILED for failure.
*/
uint8 osal_nv_read( uint16 id, uint16 ndx, uint16 len, void *buf )
{
uint32 addr;
uint16 offset;
uint8 *ptr = (uint8 *)buf;
if ( id == ZCD_NV_EXTADDR )
{
offset = OSAL_NV_IEEE_OFFSET;
findPg = OSAL_NV_IEEE_PAGE;
}
else
{
offset = findItem( id );
}
if ( offset == OSAL_NV_ITEM_NULL )
{
return NV_OPER_FAILED;
}
addr = OSAL_NV_PAGE_TO_ADDR( findPg ) + offset + ndx;
while ( len-- )
{
*ptr++ = GetCodeByte( addr++ );
}
return ZSUCCESS;
}
/*********************************************************************
*********************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -