stm25pconfigp.nc
来自「tinyos-2.x.rar」· NC 代码 · 共 475 行
NC
475 行
/*
* 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.4 $ $Date: 2006/12/12 18:23:12 $
*/
#include <Stm25p.h>
module Stm25pConfigP {
provides interface Mount[ uint8_t client ];
provides interface ConfigStorage as Config[ uint8_t client ];
uses interface Stm25pSector as Sector[ uint8_t client ];
uses interface Resource as ClientResource[ uint8_t client ];
uses interface Leds;
}
implementation {
enum {
NUM_CLIENTS = uniqueCount( "Stm25p.Config" ),
CONFIG_SIZE = 2048,
CHUNK_SIZE_LOG2 = 8,
CHUNK_SIZE = 1 << CHUNK_SIZE_LOG2,
NUM_CHUNKS = CONFIG_SIZE / CHUNK_SIZE,
BUF_SIZE = 16,
INVALID_VERSION = -1,
};
enum {
S_IDLE,
S_MOUNT,
S_READ,
S_WRITE,
S_COMMIT,
};
typedef struct {
uint16_t addr;
void* buf;
uint16_t len;
uint8_t req;
} config_state_t;
config_state_t m_config_state[ NUM_CLIENTS ];
config_state_t m_req;
typedef struct {
uint16_t chunk_addr[ NUM_CHUNKS ];
uint16_t write_addr;
int16_t version;
uint8_t cur_sector;
bool valid : 1;
} config_info_t;
config_info_t m_config_info[ NUM_CLIENTS ];
typedef struct {
int32_t version;
uint16_t crc;
} config_metadata_t;
config_metadata_t m_metadata[ 2 ];
uint8_t m_buf[ BUF_SIZE ];
uint16_t m_chunk;
uint16_t m_offset;
enum {
S_COPY_BEFORE,
S_COPY_AFTER,
};
uint8_t m_meta_state;
error_t newRequest( uint8_t client );
void continueMount( uint8_t id );
void continueWrite( uint8_t id );
void continueCommit( uint8_t id );
void signalDone( uint8_t id, error_t error );
command error_t Mount.mount[ uint8_t client ]() {
if ( call Sector.getNumSectors[ client ]() != 2 )
return ESIZE;
m_req.req = S_MOUNT;
return newRequest( client );
}
command error_t Config.read[ uint8_t client ]( storage_addr_t addr,
void* buf,
storage_len_t len ) {
if ( !m_config_info[ client ].valid )
return FAIL;
m_req.req = S_READ;
m_req.addr = addr;
m_req.buf = buf;
m_req.len = len;
return newRequest( client );
}
command error_t Config.write[ uint8_t client ]( storage_addr_t addr,
void* buf,
storage_len_t len ) {
m_req.req = S_WRITE;
m_req.addr = addr;
m_req.buf = buf;
m_req.len = len;
return newRequest( client );
}
command error_t Config.commit[ uint8_t client ]() {
m_req.req = S_COMMIT;
return newRequest( client );
}
command storage_len_t Config.getSize[ uint8_t client ]() {
return CONFIG_SIZE;
}
command bool Config.valid[ uint8_t client ]() {
return m_config_info[ client ].valid;
}
error_t newRequest( uint8_t client ) {
if ( m_config_state[ client ].req != S_IDLE )
return EBUSY;
call ClientResource.request[ client ]();
m_config_state[ client ] = m_req;
return SUCCESS;
}
stm25p_addr_t calcAddr( uint8_t id, uint16_t addr, bool current ) {
stm25p_addr_t result = addr;
if ( !(current ^ m_config_info[ id ].cur_sector) )
result += STM25P_SECTOR_SIZE;
return result;
}
event void ClientResource.granted[ uint8_t id ]() {
m_chunk = 0;
m_offset = 0;
switch( m_config_state[ id ].req ) {
case S_IDLE:
break;
case S_MOUNT:
continueMount( id );
break;
case S_READ:
call Sector.read[ id ]( calcAddr( id, m_config_state[ id ].addr, TRUE ),
m_config_state[ id ].buf,
m_config_state[ id ].len );
break;
case S_WRITE:
m_meta_state = S_COPY_BEFORE;
m_chunk = m_config_state[ id ].addr >> CHUNK_SIZE_LOG2;
continueWrite( id );
break;
case S_COMMIT:
continueCommit( id );
break;
}
}
void continueMount( uint8_t id ) {
uint32_t addr = 0;
uint8_t cur_sector = 0;
int i;
switch( m_chunk ) {
case 1:
addr = STM25P_SECTOR_SIZE;
// fall through
case 0:
addr += STM25P_SECTOR_SIZE - sizeof( config_metadata_t );
call Sector.read[ id ]( addr, (uint8_t*)&m_metadata[ m_chunk ],
sizeof( config_metadata_t ) );
break;
case 3:
addr = STM25P_SECTOR_SIZE;
// fall through
case 2:
call Sector.computeCrc[ id ]( 0, addr, CONFIG_SIZE );
break;
case 4:
if ( m_metadata[ 0 ].version != INVALID_VERSION ||
m_metadata[ 1 ].version != INVALID_VERSION ) {
m_config_info[ id ].valid = TRUE;
if ( m_metadata[ 0 ].version == INVALID_VERSION )
cur_sector = 1;
else if ( m_metadata[ 1 ].version == INVALID_VERSION )
cur_sector = 0;
else
cur_sector = (( m_metadata[1].version - m_metadata[0].version ) > 0);
}
m_config_info[ id ].cur_sector = cur_sector;
m_config_info[ id ].version = m_metadata[ cur_sector ].version;
call Sector.erase[ id ]( !cur_sector, 1 );
break;
case 5:
// initialize chunk addrs
for ( i = 0; i < NUM_CHUNKS; i++ )
m_config_info[ id ].chunk_addr[ i ] = i << CHUNK_SIZE_LOG2;
m_config_info[ id ].write_addr = CONFIG_SIZE;
signalDone( id, SUCCESS );
break;
}
m_chunk++;
}
event void Sector.readDone[ uint8_t id ]( stm25p_addr_t addr, uint8_t* buf,
stm25p_len_t len, error_t error ) {
switch ( m_config_state[ id ].req ) {
case S_IDLE:
break;
case S_MOUNT:
continueMount( id );
break;
case S_READ:
signalDone( id, error );
break;
case S_WRITE:
addr = calcAddr( id, m_config_info[ id ].write_addr, FALSE );
call Sector.write[ id ]( addr, buf, len );
break;
case S_COMMIT:
addr = ((uint16_t)m_chunk << CHUNK_SIZE_LOG2) + m_offset;
addr = calcAddr( id, addr, FALSE );
call Sector.write[ id ]( addr, buf, len );
break;
}
}
void continueWrite( uint8_t id ) {
config_state_t* state = &m_config_state[ id ];
config_info_t* info = &m_config_info[ id ];
uint8_t chunk = m_chunk + (m_offset / CHUNK_SIZE);
uint8_t offset = m_offset & 0xff;
uint32_t addr;
uint16_t len;
// compute addr for copy
addr = info->chunk_addr[ chunk ] + offset;
addr = calcAddr( id, addr, info->chunk_addr[ chunk ] < CONFIG_SIZE );
switch( m_meta_state ) {
case S_COPY_BEFORE:
// copy old data before
if ( offset < (uint8_t)state->addr ) {
len = (uint8_t)state->addr - offset;
if ( len > sizeof( m_buf ) )
len = sizeof( m_buf );
call Sector.read[ id ]( addr, m_buf, len );
}
// write new data
else if ( offset == (uint8_t)state->addr ) {
addr = calcAddr( id, info->write_addr, FALSE );
len = state->len;
call Sector.write[ id ]( addr, state->buf, len );
m_meta_state = S_COPY_AFTER;
}
break;
case S_COPY_AFTER:
// copy old data after
if ( offset != 0 ) {
len = CHUNK_SIZE - offset;
if ( len > sizeof( m_buf ) )
len = sizeof( m_buf );
call Sector.read[ id ]( addr, m_buf, len );
}
// all done, update chunk addrs
else {
info->write_addr -= m_offset;
for ( chunk = 0; chunk < m_offset / CHUNK_SIZE; chunk++ ) {
info->chunk_addr[ m_chunk+chunk ] = info->write_addr;
info->write_addr += CHUNK_SIZE;
}
signalDone( id, SUCCESS );
}
break;
}
}
event void Sector.writeDone[ uint8_t id ]( stm25p_addr_t addr, uint8_t* buf,
stm25p_len_t len, error_t error ){
switch( m_config_state[ id ].req ) {
case S_WRITE:
m_config_info[ id ].write_addr += len;
m_offset += len;
continueWrite( id );
break;
case S_COMMIT:
m_offset += len;
continueCommit( id );
break;
}
}
event void Sector.eraseDone[ uint8_t id ]( uint8_t sector,
uint8_t num_sectors,
error_t error ) {
if ( m_config_state[ id ].req == S_MOUNT )
continueMount( id );
else
continueCommit( id );
}
void continueCommit( uint8_t id ) {
config_info_t* info = &m_config_info[ id ];
uint32_t addr;
uint16_t len;
int i;
// check if time to copy next chunk
if ( m_offset >= CHUNK_SIZE ) {
m_chunk++;
m_offset = 0;
}
// copy data
if ( m_chunk < NUM_CHUNKS ) {
// compute addr for copy
addr = info->chunk_addr[ m_chunk ] + m_offset;
addr = calcAddr( id, addr, info->chunk_addr[ m_chunk ] < CONFIG_SIZE );
len = sizeof( m_buf );
call Sector.read[ id ]( addr, m_buf, len );
}
// compute crc
else if ( m_chunk == NUM_CHUNKS ) {
addr = calcAddr( 0, 0, FALSE );
call Sector.computeCrc[ id ]( 0, addr, CONFIG_SIZE );
m_chunk++;
}
// swap and erase other sector
else if ( m_chunk == NUM_CHUNKS + 1 ) {
info->cur_sector ^= 1;
info->write_addr = CONFIG_SIZE;
// initialize chunks
for ( i = 0; i < NUM_CHUNKS; i++ )
info->chunk_addr[ i ] = (uint16_t)i << CHUNK_SIZE_LOG2;
call Sector.erase[ id ]( !info->cur_sector, 1 );
m_chunk++;
}
// signal done
else {
m_config_info[ id ].valid = TRUE;
signalDone( id, SUCCESS );
}
}
event void Sector.computeCrcDone[ uint8_t id ]( stm25p_addr_t addr,
stm25p_len_t len,
uint16_t crc,
error_t error ) {
// mount
if ( m_config_state[ id ].req == S_MOUNT ) {
uint8_t chunk = addr >> STM25P_SECTOR_SIZE_LOG2;
if ( m_metadata[ chunk ].crc != crc )
m_metadata[ chunk ].version = INVALID_VERSION;
continueMount( id );
}
// commit
else {
bool cur_sector = m_config_info[ id ].cur_sector;
m_config_info[ id ].version++;
m_metadata[ !cur_sector ].version = m_config_info[ id ].version;
m_metadata[ !cur_sector ].crc = crc;
addr += STM25P_SECTOR_SIZE - sizeof( config_metadata_t );
call Sector.write[ id ]( addr, (uint8_t*)&m_metadata[ !cur_sector ],
sizeof( config_metadata_t ) );
}
}
void signalDone( uint8_t id, error_t error ) {
uint8_t req = m_config_state[ id ].req;
call ClientResource.release[ id ]();
m_config_state[ id ].req = S_IDLE;
switch( req ) {
case S_MOUNT:
signal Mount.mountDone[ id ]( error );
break;
case S_READ:
signal Config.readDone[ id ]( m_config_state[ id ].addr,
m_config_state[ id ].buf,
m_config_state[ id ].len, error );
break;
case S_WRITE:
signal Config.writeDone[ id ]( m_config_state[ id ].addr,
m_config_state[ id ].buf,
m_config_state[ id ].len, error );
break;
case S_COMMIT:
signal Config.commitDone[ id ]( error );
break;
}
}
default event void Mount.mountDone[ uint8_t id ]( error_t error ) {}
default event void Config.readDone[ uint8_t id ]( storage_addr_t addr, void* buf, storage_len_t len, error_t error ) {}
default event void Config.writeDone[ uint8_t id ]( storage_addr_t addr, void* buf, storage_len_t len, error_t error ) {}
default event void Config.commitDone[ uint8_t id ]( error_t error ) {}
default command storage_addr_t Sector.getPhysicalAddress[ uint8_t id ]( storage_addr_t addr ) { return 0xffffffff; }
default command uint8_t Sector.getNumSectors[ uint8_t id ]() { return 0; }
default command error_t Sector.read[ uint8_t id ]( storage_addr_t addr, uint8_t* buf, storage_len_t len ) { return FAIL; }
default command error_t Sector.write[ uint8_t id ]( storage_addr_t addr, uint8_t* buf, storage_len_t len ) { return FAIL; }
default command error_t Sector.erase[ uint8_t id ]( uint8_t sector, uint8_t num_sectors ) { return FAIL; }
default command error_t Sector.computeCrc[ uint8_t id ]( uint16_t crc, storage_addr_t addr, storage_len_t len ) { return FAIL; }
default async command error_t ClientResource.request[ uint8_t id ]() { return FAIL; }
default async command error_t ClientResource.release[ uint8_t id ]() { return FAIL; }
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?