/********************************************************************* * @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. * @param flag - TRUE if the checksum should be written, FALSE otherwise. * * @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, uint8 flag ) { uint16 offset = pgOff[pg-OSAL_NV_PAGE_BEG]; uint8 rtrn = FALSE; osalNvHdr_t hdr; hdr.id = id; hdr.len = len; writeWord( pg, offset, (uint8 *)&hdr ); HalFlashRead(pg, offset, (uint8 *)(&hdr), OSAL_NV_HDR_SIZE); if ( (hdr.id == id) && (hdr.len == len) ) { if ( flag ) { hdr.chk = calcChkB( len, buf ); offset += OSAL_NV_HDR_SIZE; if ( buf != NULL ) { writeBuf( pg, offset, len, buf ); } if ( hdr.chk == calcChkF( pg, offset, len ) ) { if ( hdr.chk == setChk( pg, offset, hdr.chk ) ) { hotItemUpdate(pg, offset, hdr.id); rtrn = TRUE; } } } else { rtrn = TRUE; } len = OSAL_NV_ITEM_SIZE( hdr.len ); } else { len = OSAL_NV_ITEM_SIZE( hdr.len ); if (len > (OSAL_NV_PAGE_SIZE - pgOff[pg - OSAL_NV_PAGE_BEG])) { len = (OSAL_NV_PAGE_SIZE - pgOff[pg - OSAL_NV_PAGE_BEG]); } pgLost[pg - OSAL_NV_PAGE_BEG] += len; } pgOff[pg - OSAL_NV_PAGE_BEG] += len; return rtrn; }
/********************************************************************* * @fn initItem * * @brief An NV item is created and initialized with the data passed to the function, if any. * * @param id - Valid NV item Id. * @param len - Item data length. * @param *buf - Pointer to item initalization data. Set to NULL if none. * * @return TRUE if item write and read back checksums ok; FALSE otherwise. */ static uint8 initItem( uint8 flag, uint16 id, uint16 len, void *buf ) { uint16 sz = OSAL_NV_ITEM_SIZE( len ); uint8 rtrn = FALSE; uint8 cnt = OSAL_NV_PAGES_USED; uint8 pg = pgRes+1; // Set to 1 after the reserve page to even wear across all available pages. uint8 idx; do { if (pg >= OSAL_NV_PAGE_BEG+OSAL_NV_PAGES_USED) { pg = OSAL_NV_PAGE_BEG; } if ( pg != pgRes ) { idx = pg - OSAL_NV_PAGE_BEG; if ( (pgOff[idx] - pgLost[idx] + sz) <= OSAL_NV_PAGE_FREE ) { break; } } pg++; } while (--cnt); if (cnt) { // Item fits if an old page is compacted. if ( (pgOff[idx] + sz) > OSAL_NV_PAGE_FREE ) { pg = pgRes; } // New item is the first one written to the reserved page, then the old page is compacted. rtrn = writeItem( pg, id, len, buf, flag ); if ( pg == pgRes ) { if ( flag ) { compactPage( OSAL_NV_PAGE_BEG+idx ); } else { *(uint8 *)buf = OSAL_NV_PAGE_BEG+idx; } } } return rtrn; }
/********************************************************************* * @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; }