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

📄 p30logp.nc

📁 tinyos2.0版本驱动
💻 NC
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2005 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 Kaisen Lin * @author Phil Buonadonna * */#include <P30.h>#include <StorageVolumes.h>module P30LogP {  provides interface LogRead as Read[ storage_volume_t block ];  provides interface LogWrite as Write[ storage_volume_t block ];  uses interface Leds;  uses interface Flash;  uses interface Get<bool> as Circular[ storage_volume_t block ];}implementation {#define SEEK_BEGINNING (0x0)#define SEEK_EOL (0xFFFFFFFF)#define L_BASE_BLOCK(_x) (P30_VMAP[_x].base * FLASH_PARTITION_SIZE)#define L_PARTITIONS(_x) ((P30_VMAP[_x].size * FLASH_PARTITION_SIZE) / P30_BLOCK_SIZE)#define L_FULL_RECORD_SIZE (sizeof(record_data_t) + sizeof(record_meta_t))#define L_RECORD_DATA_SIZE 256#define L_MAX_RECORDS_PER_BLOCK (P30_BLOCK_SIZE / L_FULL_RECORD_SIZE) // page meta counts as one record  // _a = blockId (from parameterized interface), _b = page, _c = record#define L_RAW_OFFSET(_a,_b,_c) (L_BASE_BLOCK(_a) + (_b * P30_BLOCK_SIZE) + (_c * L_FULL_RECORD_SIZE))  enum {    INVALID_VERSION = 0xFFFFFFFF,    NUM_VOLS = _V_NUMVOLS_, //uniqueCount("pxa27xp30.Volume"),  };  enum {    PAGE_START = 0x0000,    PAGE_USED = 0xFFF0,    PAGE_AVAILABLE = 0xFFFF,  };  typedef struct page_meta_t {    uint16_t header;  } page_meta_t;  enum {    RECORD_VALID = 0x0000,    RECORD_INVALID = 0xFFF0,    RECORD_EMPTY = 0xFFFF,  };  typedef struct record_meta_t {    uint16_t status;    uint16_t length;  } record_meta_t;  typedef struct record_data_t {    uint8_t data[L_RECORD_DATA_SIZE];  } record_data_t;  typedef enum {    S_IDLE,    S_READ,    S_APPEND,    S_SYNC,    S_ERASE,    S_SEEK,  } p30_log_state_t;  norace p30_log_state_t m_state = S_IDLE;  storage_volume_t clientId = 0xff;  void* clientBuf;  storage_len_t clientLen;  error_t clientResult;  uint32_t firstBlock[NUM_VOLS]; // 0-15 for 2 MB  uint32_t lastBlock[NUM_VOLS]; // 0-15 for 2 MB  uint32_t nextFreeRecord[NUM_VOLS]; // 0-X depending on data size  storage_cookie_t readCookieOffset[NUM_VOLS]; // this is a raw offset  bool gbOverwriteOccured = FALSE;  /* This shuffles all the blocks when we run out of space. We have to   * do it in a special order so crash recovery is possible. We also   * have to write special bytes so we can rewrite to areas without   * doing a complete erase.   */  void shuffleBlocks(storage_volume_t block) {    page_meta_t pageMeta;    uint32_t pageCounter;    // 1. set the last block to USED, if it's already USED or START, then no effect    pageMeta.header = PAGE_USED;    call Flash.write(L_RAW_OFFSET(block, lastBlock[block], 0),		     (uint8_t*) &pageMeta,		     sizeof(page_meta_t));    // 2. if lastBlock + 1 is free, then set it as last block and the first record is free    pageCounter = (lastBlock[block] + 1) % L_PARTITIONS(block);    call Flash.read(L_RAW_OFFSET(block, pageCounter, 0),		    (uint8_t*) &pageMeta,		    sizeof(page_meta_t));    if(pageMeta.header == PAGE_AVAILABLE) {      nextFreeRecord[block] = 1;      lastBlock[block] = pageCounter;    }    else {      call Flash.erase(L_RAW_OFFSET(block, firstBlock[block], 0));      pageCounter = (firstBlock[block] + 1) % L_PARTITIONS(block);      pageMeta.header = PAGE_START;      call Flash.write(L_RAW_OFFSET(block, pageCounter, 0),		       (uint8_t*) &pageMeta,		       sizeof(page_meta_t));      nextFreeRecord[block] = 1;      lastBlock[block] = firstBlock[block];      firstBlock[block] = pageCounter;      gbOverwriteOccured = TRUE;    }  }  /*   * Converts a cookie to a page/record/offset tuple   */  void cookieToTuple(uint32_t cookie, storage_volume_t block,		     uint32_t *page, uint32_t *record, uint32_t *offset) {    uint32_t mypage;    uint32_t myrecord;    uint32_t myoffset;    mypage = (cookie - L_BASE_BLOCK(block)) / P30_BLOCK_SIZE;    cookie = (cookie - L_BASE_BLOCK(block)) % P30_BLOCK_SIZE;    myrecord = cookie / L_FULL_RECORD_SIZE;    myoffset = (cookie % L_FULL_RECORD_SIZE) - sizeof(record_meta_t);    *page = mypage;    *record = myrecord;    *offset = myoffset;  }  /*   * Ideally, Logstorage would require a mount too, but it doesn't so   * it's a total hack. Before any operation, we have to check if a   * mount occurred. Mount initializes the your logblock.   */  uint8_t mountBits[NUM_VOLS];  void myMount(storage_volume_t block) {    page_meta_t pageMeta;    record_meta_t recordMeta;    uint32_t pageCounter;    uint32_t recordCounter;    uint32_t freePages = 0;    if(mountBits[block] != 0)      return;    // scan all 128k pages for page meta    // annoying corner case of all free pages, write the first page as START    for(pageCounter = 0; pageCounter < L_PARTITIONS(block); pageCounter++) {      call Flash.read(L_RAW_OFFSET(block, pageCounter, 0),		      (uint8_t*)&pageMeta,		      sizeof(page_meta_t));      if(pageMeta.header == PAGE_AVAILABLE)	freePages++;    }    if(freePages == L_PARTITIONS(block)) {      pageMeta.header = PAGE_START;      call Flash.write(L_RAW_OFFSET(block, 0, 0), (uint8_t*) &pageMeta, sizeof(page_meta_t));    }    // if we find a START page, then we are done    for(pageCounter = 0; pageCounter < L_PARTITIONS(block); pageCounter++) {      call Flash.read(L_RAW_OFFSET(block, pageCounter, 0),		      (uint8_t*)&pageMeta,		      sizeof(page_meta_t));      if(pageMeta.header == PAGE_START) {	firstBlock[block] = pageCounter;	break;      }    }    // if we didn't find a START page, first page is right after AVAILABLE    if(pageCounter == L_PARTITIONS(block)) {      for(pageCounter = 0; pageCounter < L_PARTITIONS(block); pageCounter++) {	call Flash.read(L_RAW_OFFSET(block, pageCounter, 0),			(uint8_t*)&pageMeta,			sizeof(page_meta_t));	if(pageMeta.header == PAGE_AVAILABLE) {	  pageCounter = (pageCounter + 1) % L_PARTITIONS(block);	  firstBlock[block] = pageCounter;	  // mark that block as a START block	  pageMeta.header = PAGE_START;	  call Flash.write(L_RAW_OFFSET(block, pageCounter, 0),			   (uint8_t*) &pageMeta,			   sizeof(page_meta_t));	  break;	}      }    }    // now we scan for next free record location    pageCounter = firstBlock[block];    for(recordCounter = 1; recordCounter < L_MAX_RECORDS_PER_BLOCK; recordCounter++) {      call Flash.read(L_RAW_OFFSET(block, pageCounter, recordCounter),		      (uint8_t*) &recordMeta,		      sizeof(record_meta_t));      if(recordMeta.status == RECORD_EMPTY) {	nextFreeRecord[block] = recordCounter;	lastBlock[block] = pageCounter;	break;      }    }    // Didn't find a free record in the START block, search the first FREE block    if(recordCounter == L_MAX_RECORDS_PER_BLOCK) {      for(pageCounter = 0; pageCounter < L_PARTITIONS(block); pageCounter++) {	call Flash.read(L_RAW_OFFSET(block, pageCounter, 0),			(uint8_t*)&pageMeta,			sizeof(page_meta_t));	if(pageMeta.header == PAGE_AVAILABLE) {	  for(recordCounter = 1; recordCounter < L_MAX_RECORDS_PER_BLOCK; recordCounter++) {	    call Flash.read(L_RAW_OFFSET(block, pageCounter, recordCounter),			    (uint8_t*) &recordMeta,			    sizeof(record_meta_t));	    if(recordMeta.status == RECORD_EMPTY) {	      lastBlock[block] = pageCounter;	      nextFreeRecord[block] = recordCounter;	      goto mount_complete;	    }	  }	}      }      // if here, you didn't find the last block, it must be right before the START block      // special case the wrap around      if(firstBlock[block] == 0)	lastBlock[block] = L_PARTITIONS(block) - 1;      else	lastBlock[block] = firstBlock[block] - 1;      // that last block must be full, so shuffle it      shuffleBlocks(block);    }  mount_complete:    readCookieOffset[block] = SEEK_BEGINNING;    mountBits[block] = 1;  }  task void signalDoneTask() {    switch(m_state) {    case S_APPEND:      m_state = S_IDLE;      signal Write.appendDone[clientId](clientBuf, clientLen, gbOverwriteOccured, clientResult);      gbOverwriteOccured = FALSE;      break;    case S_SYNC:      m_state = S_IDLE;      signal Write.syncDone[clientId](SUCCESS);      break;    case S_ERASE:      m_state = S_IDLE;      signal Write.eraseDone[clientId](clientResult);      break;   case S_READ:      m_state = S_IDLE;      signal Read.readDone[clientId](clientBuf, clientLen, clientResult);      break;   case S_SEEK:      m_state = S_IDLE;      signal Read.seekDone[clientId](SUCCESS);      break;    default:      break;    }

⌨️ 快捷键说明

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