⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 osal_nv.c

📁 用IAR开发的ZIGBEE网络路由例子
💻 C
📖 第 1 页 / 共 3 页
字号:
  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 + -