Ejemplo n.º 1
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;
}
Ejemplo n.º 2
0
/*********************************************************************
 * @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;
}
Ejemplo n.º 3
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;
}