stm25plogp.nc

来自「tinyos-2.x.rar」· NC 代码 · 共 533 行 · 第 1/2 页

NC
533
字号
/*
 * Copyright (c) 2005-2006 Arch Rock Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the
 *   distribution.
 * - Neither the name of the Arch Rock Corporation nor the names of
 *   its contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * ARCHED ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE
 */

/**
 * @author Jonathan Hui <jhui@archrock.com>
 * @version $Revision: 1.8 $ $Date: 2008/09/04 17:20:59 $
 */

#include <Stm25p.h>

module Stm25pLogP {
  
  provides interface Init;
  provides interface LogRead as Read[ uint8_t id ];
  provides interface LogWrite as Write[ uint8_t id ];
  
  uses interface Stm25pSector as Sector[ uint8_t id ];
  uses interface Resource as ClientResource[ uint8_t id ];
  uses interface Get<bool> as Circular[ uint8_t id ];
  uses interface Leds;

}

implementation {

  enum {
    NUM_LOGS = uniqueCount( "Stm25p.Log" ),
    BLOCK_SIZE = 4096,
    BLOCK_SIZE_LOG2 = 12,
    BLOCK_MASK = BLOCK_SIZE - 1,
    BLOCKS_PER_SECTOR = STM25P_SECTOR_SIZE / BLOCK_SIZE,
    MAX_RECORD_SIZE = 254,
    INVALID_HEADER = 0xff,
  };
  
  typedef enum {
    S_IDLE,
    S_READ,
    S_SEEK,
    S_ERASE,
    S_APPEND,
    S_SYNC,
  } stm25p_log_req_t;

  typedef struct stm25p_log_state_t {
    storage_cookie_t cookie;
    void* buf;
    uint8_t len;
    stm25p_log_req_t req;
  } stm25p_log_state_t;

  typedef struct stm25p_log_info_t {
    stm25p_addr_t read_addr;
    stm25p_addr_t remaining;
    stm25p_addr_t write_addr;
  } stm25p_log_info_t;
  
  stm25p_log_state_t m_log_state[ NUM_LOGS ];
  stm25p_log_state_t m_req;
  stm25p_log_info_t m_log_info[ NUM_LOGS ];
  stm25p_addr_t m_addr;
  bool m_records_lost;
  uint8_t m_header;
  uint8_t m_len;

  typedef enum {
    S_SEARCH_BLOCKS,
    S_SEARCH_RECORDS,
    S_SEARCH_SEEK,
    S_HEADER,
    S_DATA,
  } stm25p_log_rw_state_t;

  stm25p_log_rw_state_t m_rw_state;

  error_t newRequest( uint8_t client );
  void continueReadOp( uint8_t client );
  void continueAppendOp( uint8_t client );
  void signalDone( uint8_t id, error_t error );
  
  command error_t Init.init() {
    int i;
    for ( i = 0; i < NUM_LOGS; i++ ) {
      m_log_info[ i ].read_addr = STM25P_INVALID_ADDRESS;
      m_log_info[ i ].write_addr = 0;
    }
    return SUCCESS;
  }
  
  command error_t Read.read[ uint8_t id ]( void* buf, storage_len_t len ) {
    
    m_req.req = S_READ;
    m_req.buf = buf;
    m_req.len = len;
    m_len = len;
    return newRequest( id );
    
  }
  
  command error_t Read.seek[ uint8_t id ]( storage_addr_t cookie ) {
    
    if ( cookie > m_log_info[ id ].write_addr )
      return FAIL;
    
    m_req.req = S_SEEK;
    m_req.cookie = cookie;
    return newRequest( id );
    
  }
  
  command storage_cookie_t Read.currentOffset[ uint8_t id ]() {
    return m_log_info[ id ].read_addr;
  }
  
  command storage_cookie_t Read.getSize[ uint8_t id ]() {
    return ( (storage_len_t)call Sector.getNumSectors[ id ]()
             << STM25P_SECTOR_SIZE_LOG2 );
  }
  
  command storage_cookie_t Write.currentOffset[ uint8_t id ]() {
    return m_log_info[ id ].write_addr;
  }
  
  command error_t Write.erase[ uint8_t id ]() {
    m_req.req = S_ERASE;
    return newRequest( id );
  }
  
  command error_t Write.append[ uint8_t id ]( void* buf, storage_len_t len ) {
    
    uint16_t bytes_left = (uint16_t)m_log_info[ id ].write_addr % BLOCK_SIZE;
    bytes_left = BLOCK_SIZE - bytes_left;
    
    // don't allow appends larger than maximum record size
    if ( len > MAX_RECORD_SIZE )
      return ESIZE;
    
    // move to next block if current block doesn't have enough space
    if ( sizeof( m_header ) + len > bytes_left )
      m_log_info[ id ].write_addr += bytes_left;
    
    // if log is not circular, make sure it doesn't grow too large
    if ( !call Circular.get[ id ]() &&
	 ( (uint8_t)(m_log_info[ id ].write_addr >> STM25P_SECTOR_SIZE_LOG2) >=
	   call Sector.getNumSectors[ id ]() ) )
      return ESIZE;
    
    m_records_lost = FALSE;
    m_req.req = S_APPEND;
    m_req.buf = buf;
    m_req.len = len;

    return newRequest( id );

  }
  
  command error_t Write.sync[ uint8_t id ]() {
    m_req.req = S_SYNC;
    return newRequest( id );
  }
  
  error_t newRequest( uint8_t client ) {
    
    if ( m_log_state[ client ].req != S_IDLE )
      return FAIL;
    
    call ClientResource.request[ client ]();
    m_log_state[ client ] = m_req;
    
    return SUCCESS;
    
  }
  
  uint8_t calcSector( uint8_t client, stm25p_addr_t addr ) {
    uint8_t sector = call Sector.getNumSectors[ client ]();
    return (uint8_t)(( addr >> STM25P_SECTOR_SIZE_LOG2 ) % sector);
  }

  stm25p_addr_t calcAddr( uint8_t client, stm25p_addr_t addr  ) {
    stm25p_addr_t result = calcSector( client, addr );
    result <<= STM25P_SECTOR_SIZE_LOG2;
    result |= addr & STM25P_SECTOR_MASK;
    return result;
  }

  event void ClientResource.granted[ uint8_t id ]() {

    // log never used, need to find start and end of log
    if ( m_log_info[ id ].read_addr == STM25P_INVALID_ADDRESS &&
	 m_log_state[ id ].req != S_ERASE ) {
      m_rw_state = S_SEARCH_BLOCKS;
      call Sector.read[ id ]( 0, (uint8_t*)&m_addr, sizeof( m_addr ) );
    }
    // start and end of log known, do the requested operation
    else {
      switch( m_log_state[ id ].req ) {
      case S_READ:
	m_rw_state = (m_log_info[ id ].remaining) ? S_DATA : S_HEADER;
	continueReadOp( id );
	break;
      case S_SEEK:
	{
	  // make sure the cookie is still within the range of valid data
	  uint8_t numSectors = call Sector.getNumSectors[ id ]();
	  uint8_t readSector = 
	    (m_log_state[ id ].cookie >> STM25P_SECTOR_SIZE_LOG2);
	  uint8_t writeSector =
	    ((m_log_info[ id ].write_addr-1)>>STM25P_SECTOR_SIZE_LOG2)+1;
	  // if cookie is overwritten, advance to beginning of log
	  if ( (writeSector - readSector) > numSectors ) {
	    m_log_state[ id ].cookie = 
	      (storage_cookie_t)(writeSector-numSectors)
		<<STM25P_SECTOR_SIZE_LOG2;
	  }
	  m_log_info[ id ].read_addr = m_log_state[ id ].cookie & ~BLOCK_MASK;
	  m_log_info[ id ].remaining = 0;
	  m_rw_state = S_SEARCH_SEEK;
	  if ( m_log_info[ id ].read_addr != m_log_state[ id ].cookie ) {
	    m_log_info[ id ].read_addr += sizeof( m_addr );
	    call Sector.read[ id ]( calcAddr( id, m_log_info[ id ].read_addr ),
				    &m_header, sizeof( m_header ) );
	  }
	  else
	    signalDone( id, SUCCESS );
	}
	break;
      case S_ERASE:
	call Sector.erase[ id ]( 0, call Sector.getNumSectors[ id ]() );
	break;
      case S_APPEND:
	m_rw_state = S_HEADER;
	continueAppendOp( id );
	break;
      case S_SYNC:
	signalDone( id, SUCCESS );
	break;
      case S_IDLE:
	break;
      }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?