Beispiel #1
0
/*********************************************************************
 * @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      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;
}
Beispiel #3
0
/*********************************************************************
 * @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;
}
Beispiel #4
0
/*********************************************************************
 * @fn      initNV
 *
 * @brief   Initialize the NV flash pages.
 *
 * @param   none
 *
 * @return  TRUE
 */
static uint8 initNV( void )
{
  osalNvPgHdr_t pgHdr;
  uint8 oldPg = OSAL_NV_PAGE_NULL;
  uint8 newPg = OSAL_NV_PAGE_NULL;
  uint8 findDups = FALSE;
  uint8 pg;

  pgRes = OSAL_NV_PAGE_NULL;

  for ( pg = OSAL_NV_PAGE_BEG; pg <= OSAL_NV_PAGE_END; pg++ )
  {
    HalFlashRead(pg, OSAL_NV_PAGE_HDR_OFFSET, (uint8 *)(&pgHdr), OSAL_NV_HDR_SIZE);

    if ( pgHdr.active == OSAL_NV_ERASED_ID )
    {
      if ( pgRes == OSAL_NV_PAGE_NULL )
      {
        pgRes = pg;
      }
      else
      {
        setPageUse( pg, TRUE );
      }
    }
    else  // Page is active.
    {
      // If the page is not yet in use, it is the tgt of items from an xfer.
      if ( pgHdr.inUse == OSAL_NV_ERASED_ID )
      {
        newPg = pg;
      }
      // An Xfer from this page was in progress.
      else if ( pgHdr.xfer != OSAL_NV_ERASED_ID )
      {
        oldPg = pg;
      }
    }

    // Calculate page offset and lost bytes - any "old" item triggers an N^2 re-scan from start.
    if ( initPage( pg, OSAL_NV_ITEM_NULL, findDups ) != OSAL_NV_ITEM_NULL )
    {
      findDups = TRUE;
      pg = OSAL_NV_PAGE_BEG-1;
      continue;
    }
  }  // for ( pg = OSAL_NV_PAGE_BEG; pg <= OSAL_NV_PAGE_END; pg++ )

  /* First the old page is erased, and then the new page is put into use.
   * So if a transfer was in progress, the new page will always not yet be
   * marked as in use, since that is the last step to ending a transfer.
   */
  if ( newPg != OSAL_NV_PAGE_NULL )
  {
    /* If there is already a fallow page reserved, keep it and put the newPg in use.
     * An unfinished compaction will finish to the new reserve page and the old page
     * will be erased and reserved.
     */
    if ( pgRes != OSAL_NV_PAGE_NULL )
    {
      setPageUse( newPg, TRUE );
    }
    /* If setting old page to 'xfer' failed or board reset before it was effected, there is no way
     * to know which page was the 'old page' - so just reset all NV pages to start clean.
     */
    else if ( oldPg != OSAL_NV_PAGE_NULL )
    {
      pgRes = newPg;
    }

    /* If a page compaction was interrupted and the page being compacted is not
     * yet erased, then there may be items remaining to xfer before erasing.
     */
    if ( oldPg != OSAL_NV_PAGE_NULL )
    {
      compactPage( oldPg );
    }
  }

  /* If no page met the criteria to be the reserve page:
   *  - A compactPage() failed or board reset before doing so.
   *  - Perhaps the user changed which Flash pages are dedicated to NV and downloaded the code
   *    without erasing Flash?
   */
  if ( pgRes == OSAL_NV_PAGE_NULL )
  {
    for ( pg = OSAL_NV_PAGE_BEG; pg <= OSAL_NV_PAGE_END; pg++ )
    {
      erasePage( pg );
    }
    initNV();
  }

  return TRUE;
}
Beispiel #5
0
/*********************************************************************
 * @fn      initNV
 *
 * @brief   Initialize the NV flash pages.
 *
 * @param   none
 *
 * @return  TRUE
 */
static uint8 initNV( void )
{
  osalNvPgHdr_t pgHdr;
  uint8 oldPg = OSAL_NV_PAGE_NULL;
  uint8 findDups = FALSE;
  uint8 pg;

  pgRes = OSAL_NV_PAGE_NULL;

  for ( pg = OSAL_NV_PAGE_BEG; pg <= OSAL_NV_PAGE_END; pg++ )
  {
    HalFlashRead(pg, OSAL_NV_PAGE_HDR_OFFSET, (uint8 *)(&pgHdr), OSAL_NV_HDR_SIZE);

    if ( pgHdr.active == OSAL_NV_ERASED_ID )
    {
      if ( pgRes == OSAL_NV_PAGE_NULL )
      {
        pgRes = pg;
      }
      else
      {
        setPageUse( pg, TRUE );
      }
    }
    // An Xfer from this page was in progress.
    else if ( pgHdr.xfer != OSAL_NV_ERASED_ID )
    {
      oldPg = pg;
    }
  }

  // If a page compaction was interrupted before the old page was erased.
  if ( oldPg != OSAL_NV_PAGE_NULL )
  {
    /* Interrupted compaction before the target of compaction was put in use;
     * so erase the target of compaction and start again.
     */
    if ( pgRes != OSAL_NV_PAGE_NULL )
    {
      erasePage( pgRes );
      (void)compactPage( oldPg, OSAL_NV_ITEM_NULL );
    }
    /* Interrupted compaction after the target of compaction was put in use,
     * but before the old page was erased; so erase it now and create a new reserve page.
     */
    else
    {
      erasePage( oldPg );
      pgRes = oldPg;
    }
  }
  else if ( pgRes != OSAL_NV_PAGE_NULL )
  {
    erasePage( pgRes );  // The last page erase could have been interrupted by a power-cycle.
  }
  /* else if there is no reserve page, COMPACT_PAGE_CLEANUP() must have succeeded to put the old
   * reserve page (i.e. the target of the compacted items) into use but got interrupted by a reset
   * while trying to erase the page to be compacted. Such a page should only contain duplicate items
   * (i.e. all items will be marked 'Xfer') and thus should have the lost count equal to the page
   * size less the page header.
   */

  for ( pg = OSAL_NV_PAGE_BEG; pg <= OSAL_NV_PAGE_END; pg++ )
  {
    // Calculate page offset and lost bytes - any "old" item triggers an N^2 re-scan from start.
    if ( initPage( pg, OSAL_NV_ITEM_NULL, findDups ) != OSAL_NV_ITEM_NULL )
    {
      findDups = TRUE;
      pg = (OSAL_NV_PAGE_BEG - 1);  // Pre-decrement so that loop increment will start over at zero.
      continue;
    }
  }

  if (findDups)
  {
    // Final pass to calculate page lost after invalidating duplicate items.
    for ( pg = OSAL_NV_PAGE_BEG; pg <= OSAL_NV_PAGE_END; pg++ )
    {
      (void)initPage( pg, OSAL_NV_ITEM_NULL, FALSE );
    }
  }

  if ( pgRes == OSAL_NV_PAGE_NULL )
  {
    uint8 idx, mostLost = 0;

    for ( idx = 0; idx < OSAL_NV_PAGES_USED; idx++ )
    {
      // Is this the page that was compacted?
      if (pgLost[idx] == (OSAL_NV_PAGE_SIZE - OSAL_NV_PAGE_HDR_SIZE))
      {
        mostLost = idx;
        break;
      }
      /* This check is not expected to be necessary because the above test should always succeed
       * with an early loop exit.
       */
      else if (pgLost[idx] > pgLost[mostLost])
      {
        mostLost = idx;
      }
    }

    pgRes = mostLost + OSAL_NV_PAGE_BEG;
    erasePage( pgRes );  // The last page erase had been interrupted by a power-cycle.
  }

  return TRUE;
}