/********************************************************************* * @fn setChk * * @brief Set the item header checksum given the data buffer offset. * * @param pg - Valid NV page. * @param offset - Valid offset into the page of the item data - the header * offset is calculated from this. * @param chk - The checksum to set. * * @return The checksum read back. */ static uint16 setChk( uint8 pg, uint16 offset, uint16 chk ) { offset -= OSAL_NV_WORD_SIZE; writeWordH( pg, offset, (uint8 *)&chk ); HalFlashRead( pg, offset, (uint8 *)(&chk), sizeof( chk ) ); return chk; }
/********************************************************************* * @fn compactPage * * @brief Compacts the page specified. * * @param srcPg - Valid NV page to erase. * * @return none */ static void compactPage( uint8 srcPg ) { uint16 dstOff = pgOff[pgRes-OSAL_NV_PAGE_BEG]; uint16 srcOff = OSAL_NV_ZEROED_ID; osalNvHdr_t hdr; // Mark page as being in process of compaction. writeWordH( srcPg, OSAL_NV_PG_XFER, (uint8*)(&srcOff) ); srcOff = OSAL_NV_PAGE_HDR_SIZE; do { uint16 sz; HalFlashRead(srcPg, srcOff, (uint8 *)(&hdr), OSAL_NV_HDR_SIZE); if ( hdr.id == OSAL_NV_ERASED_ID ) { break; } srcOff += OSAL_NV_HDR_SIZE; if ( (srcOff + hdr.len) > OSAL_NV_PAGE_FREE ) { break; } sz = OSAL_NV_DATA_SIZE( hdr.len ); if ( hdr.id != OSAL_NV_ZEROED_ID ) { if ( hdr.chk == calcChkF( srcPg, srcOff, hdr.len ) ) { setItem( srcPg, srcOff, eNvXfer ); writeBuf( pgRes, dstOff, OSAL_NV_HDR_SIZE, (byte *)(&hdr) ); dstOff += OSAL_NV_HDR_SIZE; xferBuf( srcPg, srcOff, pgRes, dstOff, sz ); dstOff += sz; } setItem( srcPg, srcOff, eNvZero ); // Mark old location as invalid. } srcOff += sz; } while ( TRUE ); pgOff[pgRes-OSAL_NV_PAGE_BEG] = dstOff; /* In order to recover from a page compaction that is interrupted, * the logic in osal_nv_init() depends upon the following order: * 1. Compacted page is erased. * 2. State of the target of compaction is changed ePgActive to ePgInUse. */ erasePage( srcPg ); // Mark the reserve page as being in use. setPageUse( pgRes, TRUE ); // Set the reserve page to be the newly erased page. pgRes = srcPg; }
/********************************************************************* * @fn initItem * * @brief An NV item is created and initialized with the data passed to the function, if any. * * @param flag - TRUE if the 'buf' parameter contains data for the call to writeItem(). * (i.e. if invoked from osal_nv_item_init() ). * FALSE if writeItem() should just write the header and the 'buf' parameter * is ok to use as a return value of the page number to be cleaned with * COMPACT_PAGE_CLEANUP(). * (i.e. if invoked from osal_nv_write() ). * @param id - Valid NV item Id. * @param len - Item data length. * @param *buf - Pointer to item initalization data. Set to NULL if none. * * @return The OSAL Nv page number if item write and read back checksums ok; * OSAL_NV_PAGE_NULL otherwise. */ static uint8 initItem( uint8 flag, uint16 id, uint16 len, void *buf ) { uint16 sz = OSAL_NV_ITEM_SIZE( len ); uint8 rtrn = OSAL_NV_PAGE_NULL; uint8 cnt = OSAL_NV_PAGES_USED; uint8 pg = pgRes+1; // Set to 1 after the reserve page to even wear across all available pages. do { if (pg >= OSAL_NV_PAGE_BEG+OSAL_NV_PAGES_USED) { pg = OSAL_NV_PAGE_BEG; } if ( pg != pgRes ) { uint8 idx = pg - OSAL_NV_PAGE_BEG; if ( sz <= (OSAL_NV_PAGE_SIZE - pgOff[idx] + pgLost[idx]) ) { break; } } pg++; } while (--cnt); if (cnt) { // Item fits if an old page is compacted. if ( sz > (OSAL_NV_PAGE_SIZE - pgOff[pg - OSAL_NV_PAGE_BEG]) ) { osalNvPgHdr_t pgHdr; /* Prevent excessive re-writes to page header caused by numerous, rapid, & successive * OSAL_Nv interruptions caused by resets. */ HalFlashRead(pg, OSAL_NV_PAGE_HDR_OFFSET, (uint8 *)(&pgHdr), OSAL_NV_PAGE_HDR_SIZE); if ( pgHdr.xfer == OSAL_NV_ERASED_ID ) { // Mark the old page as being in process of compaction. sz = OSAL_NV_ZEROED_ID; writeWordH( pg, OSAL_NV_PG_XFER, (uint8*)(&sz) ); } /* First the old page is compacted, then the new item will be the last one written to what * had been the reserved page. */ if (compactPage( pg, id )) { if ( writeItem( pgRes, id, len, buf, flag ) ) { rtrn = pgRes; } if ( flag == FALSE ) { /* Overload 'buf' as an OUT parameter to pass back to the calling function * the old page to be cleaned up. */ *(uint8 *)buf = pg; } else { /* Safe to do the compacted page cleanup even if writeItem() above failed because the * item does not yet exist since this call with flag==TRUE is from osal_nv_item_init(). */ COMPACT_PAGE_CLEANUP( pg ); } } } else { if ( writeItem( pg, id, len, buf, flag ) ) { rtrn = pg; } } } return rtrn; }