[Tinyos-commits] CVS: tinyos-1.x/tos/lib/Flash/AT45DB AT45Remap.nc, NONE, 1.1 BlockStorageC.nc, NONE, 1.1 BlockStorageM.nc, NONE, 1.1 ByteEEPROM.nc, NONE, 1.1 ByteEEPROMC.nc, NONE, 1.1 FormatStorageC.nc, NONE, 1.1 FormatStorageM.nc, NONE, 1.1 HALAT45DB.h, NONE, 1.1 HALAT45DBShare.nc, NONE, 1.1 PageEEPROM.h, NONE, 1.1 PageEEPROM.nc, NONE, 1.1 PageEEPROMShare.nc, NONE, 1.1 StorageManager.h, NONE, 1.1 StorageManagerC.nc, NONE, 1.1 StorageManagerM.nc, NONE, 1.1 Storage_chip.h, NONE, 1.1

David Gay idgay at users.sourceforge.net
Mon Jul 11 16:36:11 PDT 2005


Update of /cvsroot/tinyos/tinyos-1.x/tos/lib/Flash/AT45DB
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28470/AT45DB

Added Files:
	AT45Remap.nc BlockStorageC.nc BlockStorageM.nc ByteEEPROM.nc 
	ByteEEPROMC.nc FormatStorageC.nc FormatStorageM.nc HALAT45DB.h 
	HALAT45DBShare.nc PageEEPROM.h PageEEPROM.nc 
	PageEEPROMShare.nc StorageManager.h StorageManagerC.nc 
	StorageManagerM.nc Storage_chip.h 
Log Message:
new flash abstraction (BlockStorage only for now), + reorganisation of
duplicated files


--- NEW FILE: AT45Remap.nc ---
includes HALAT45DB;
interface AT45Remap {
  /* Returns AT45_MAX_PAGES for invalid request (out of volume) */
  command at45page_t remap(volume_t volume, at45page_t volumePage);
  command storage_addr_t volumeSize(volume_t volume);
}

--- NEW FILE: BlockStorageC.nc ---
// $Id: BlockStorageC.nc,v 1.1 2005/07/11 23:36:08 idgay Exp $
includes Storage;
#define HALAT45DB PageEEPROM
includes BlockStorage;

configuration BlockStorageC {
  provides {
    interface Mount[blockstorage_t blockId];
    interface BlockRead[blockstorage_t blockId];
    interface BlockWrite[blockstorage_t blockId];
  }
}
implementation {
  components BlockStorageM, StorageManagerC, Main;

  Mount = BlockStorageM.Mount;
  BlockWrite = BlockStorageM.BlockWrite;
  BlockRead = BlockStorageM.BlockRead;

  Main.StdControl -> StorageManagerC;
  BlockStorageM.HALAT45DB -> StorageManagerC.HALAT45DB;
  BlockStorageM.ActualMount -> StorageManagerC.Mount;
  BlockStorageM.AT45Remap -> StorageManagerC;
}

--- NEW FILE: BlockStorageM.nc ---
// $Id: BlockStorageM.nc,v 1.1 2005/07/11 23:36:08 idgay Exp $

/*									tab:4
 * "Copyright (c) 2000-2004 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 */

/*
 * @author: Jonathan Hui <jwhui at cs.berkeley.edu>
 * @author: David Gay <dgay at acm.org>
 */

includes Storage;
#define HALAT45DB PageEEPROM
includes BlockStorage;

module BlockStorageM {
  provides {
    interface Mount[blockstorage_t blockId];
    interface BlockWrite[blockstorage_t blockId];
    interface BlockRead[blockstorage_t blockId];
  }
  uses {
    interface HALAT45DB[blockstorage_t blockId];
    interface Mount as ActualMount[blockstorage_t blockId];
    interface AT45Remap;
  }
}
implementation 
{
  enum {
    S_IDLE,
    S_WRITE,
    S_ERASE,
    S_COMMIT, S_COMMIT2, S_COMMIT3,
    S_READ,
    S_VERIFY, S_VERIFY2,
    S_CRC,
  };

  uint8_t state = S_IDLE;
  uint8_t client;

  uint8_t* bufPtr;
  block_addr_t curAddr;
  block_addr_t bytesRemaining, requestedLength;
  uint16_t crc;
  block_addr_t maxAddr[uniqueCount("StorageManager")];
  uint8_t sig[8];

  void verifySignature();
  void commitSignature();
  void commitSync();

  result_t actualSignal(storage_result_t result) {
    uint8_t tmpState = state;
    block_addr_t actualLength;

    state = S_IDLE;
    actualLength = requestedLength - bytesRemaining;
    curAddr -= actualLength;
    bufPtr -= actualLength;

    switch(tmpState)
      {
      case S_READ:
	signal BlockRead.readDone[client](result, curAddr, bufPtr, actualLength);
	break;
      case S_WRITE:
	signal BlockWrite.writeDone[client](result, curAddr, bufPtr, actualLength);
	break;
      case S_ERASE:
	signal BlockWrite.eraseDone[client](result);
	break;
      case S_CRC:
	signal BlockRead.computeCrcDone[client](result, crc, curAddr, actualLength);
	break;
      case S_COMMIT: case S_COMMIT2: case S_COMMIT3:
	signal BlockWrite.commitDone[client](result);
	break;
      case S_VERIFY: case S_VERIFY2: 
	signal BlockRead.verifyDone[client](result);
	break;
      }

    return SUCCESS;
  }

  task void signalSuccess() { actualSignal(STORAGE_OK); }
  
  task void signalFail() { actualSignal(STORAGE_FAIL); }

  void signalDone(result_t result) {
    if (result == SUCCESS)
      switch (state)
	{
	case S_COMMIT: commitSignature(); break;
	case S_COMMIT2: commitSync(); break;
	case S_VERIFY: verifySignature(); break;
	case S_VERIFY2: 
	  if (crc == (sig[0] | (uint16_t)sig[1] << 8))
	    actualSignal(STORAGE_OK);
	  else
	    actualSignal(STORAGE_INVALID_CRC);
	  break;
	default: post signalSuccess(); break;
	}
    else
      post signalFail();
  }

  void check(result_t ok) {
    if (!ok)
      post signalFail();
  }

  bool admitRequest(uint8_t newState, uint8_t id) {
    if (state != S_IDLE)
      return FALSE;
    client = id;
    state = newState;
    return TRUE;
  }

  void calcRequest(block_addr_t addr, at45page_t *page,
		   at45pageoffset_t *offset, at45pageoffset_t *count) {
    *page = addr >> AT45_PAGE_SIZE_LOG2;
    *offset = addr & ((1 << AT45_PAGE_SIZE_LOG2) - 1);
    if (bytesRemaining < (1 << AT45_PAGE_SIZE_LOG2) - *offset)
      *count = bytesRemaining;
    else
      *count = (1 << AT45_PAGE_SIZE_LOG2) - *offset;
  }

  void continueRequest() {
    at45page_t page;
    at45pageoffset_t offset, count;
    uint8_t *buf = bufPtr;

    calcRequest(curAddr, &page, &offset, &count);
    bytesRemaining -= count;
    curAddr += count;
    bufPtr += count;

    switch (state)
      {
      case S_WRITE:
	check(call HALAT45DB.write[client](page, offset, buf, count));
	break;
      case S_READ:
	check(call HALAT45DB.read[client](page, offset, buf, count));
	break;
      case S_CRC: case S_COMMIT: case S_VERIFY2:
	check(call HALAT45DB.computeCrc[client](page, offset, count));
	break;
      }
  }

  result_t newRequest(uint8_t newState, uint8_t id,
		       block_addr_t addr, uint8_t* buf, block_addr_t len) {
    if (admitRequest(newState, id) == FAIL)
      return FAIL;

    curAddr = addr;
    bufPtr = buf;
    bytesRemaining = requestedLength = len;
    crc = 0;

    continueRequest();

    return SUCCESS;
  }

  command result_t BlockWrite.write[uint8_t id](block_addr_t addr, void* buf, block_addr_t len) {
    result_t ok = newRequest(S_WRITE, id, addr, buf, len);

    if (ok && addr + len > maxAddr[id])
      maxAddr[id] = addr+len;

    return ok;
  }

  command result_t BlockWrite.erase[uint8_t id]() {
    if (admitRequest(S_ERASE, id) == FAIL)
      return FAIL;

    check(call HALAT45DB.erase[client](0, AT45_ERASE));

    return SUCCESS;
  }

  command result_t BlockWrite.commit[uint8_t id]() {
    return newRequest(S_COMMIT, id, 0, NULL, maxAddr[id]);
  }

  /* Called once crc computed. Write crc + signature in block 0. */
  void commitSignature() {
    sig[0] = crc;
    sig[1] = crc >> 8;
    sig[2] = maxAddr[client];
    sig[3] = maxAddr[client] >> 8;
    sig[4] = maxAddr[client] >> 16;
    sig[5] = maxAddr[client] >> 24;
    sig[6] = 0xb1; /* block sig: b10c */
    sig[7] = 0x0c;
    state = S_COMMIT2;
    /* Note: bytesRemaining is 0, so multipageDone will go straight to
       signalDone */
    check(call HALAT45DB.write[client](0, 1 << AT45_PAGE_SIZE_LOG2, sig, sizeof sig));
  }

  /* Called once signature written. Ensure writes complete. */
  void commitSync() {
    state = S_COMMIT3;
    check(call HALAT45DB.syncAll[client]());
  }

  command uint32_t BlockRead.getSize[blockstorage_t blockId]() {
    return call AT45Remap.volumeSize(blockId);
  }

  command result_t BlockRead.read[uint8_t id](block_addr_t addr, void* buf, block_addr_t len) {
    return newRequest(S_READ, id, addr, buf, len);
  }

  command result_t BlockRead.verify[uint8_t id]() {
    if (admitRequest(S_VERIFY, id))
      {
	bytesRemaining = 0;
	check(call HALAT45DB.read[client](0, 1 << AT45_PAGE_SIZE_LOG2, sig, sizeof sig));
      }
    return SUCCESS;
  }

  /* See commitSignature */
  void verifySignature() {
    if (sig[6] == 0xb1 && sig[7] == 0x0c)
      {
	maxAddr[client] = sig[2] | (uint32_t)sig[3] << 8 |
	  (uint32_t)sig[4] << 16 | (uint32_t)sig[5] << 24;
	state = S_IDLE;
	newRequest(S_VERIFY2, client, 0, NULL, maxAddr[client]);
      }
    else
      actualSignal(STORAGE_INVALID_SIGNATURE);
  }

  command result_t BlockRead.computeCrc[uint8_t id](block_addr_t addr, block_addr_t len) {
    return newRequest(S_CRC, id, addr, NULL, len);
  }

  void multipageDone(result_t result) {
    if (bytesRemaining == 0 || result == FAIL)
      signalDone(result);
    else
      continueRequest();
  }

  event result_t HALAT45DB.writeDone[uint8_t id](result_t result) {
    if (id == client)
      multipageDone(result);
    return SUCCESS;
  }

  event result_t HALAT45DB.readDone[uint8_t id](result_t result) {
    if (id == client)
      multipageDone(result);
    return SUCCESS;
  }

  event result_t HALAT45DB.computeCrcDone[uint8_t id](result_t result, uint16_t newCrc) {
    if (id == client)
      {
	crc = crc + newCrc; // this is undoubtably horrible and wrong.
	multipageDone(result);
      }
    return SUCCESS;
  }

  event result_t HALAT45DB.eraseDone[uint8_t id](result_t result) {
    if (id == client)
      signalDone(result);
    return SUCCESS;
  }

  event result_t HALAT45DB.syncDone[uint8_t id](result_t result) {
    if (id == client)
      signalDone(result);
    return SUCCESS;
  }

  event result_t HALAT45DB.flushDone[uint8_t id](result_t result) {
    return SUCCESS;
  }

  default event void BlockWrite.writeDone[uint8_t id](storage_result_t result, block_addr_t addr, void* buf, block_addr_t len) { }
  default event void BlockWrite.eraseDone[uint8_t id](storage_result_t result) { }
  default event void BlockWrite.commitDone[uint8_t id](result_t result) { }
  default event void BlockRead.readDone[uint8_t id](storage_result_t result, block_addr_t addr, void* buf, block_addr_t len) { }
  default event void BlockRead.verifyDone[uint8_t id](result_t result) { }
  default event void BlockRead.computeCrcDone[uint8_t id](storage_result_t result, uint16_t x, block_addr_t addr, block_addr_t len) { }

  command result_t Mount.mount[blockstorage_t blockId](volume_id_t id) {
    maxAddr[id] = 0;
    return call ActualMount.mount[blockId](id);
  }

  event void ActualMount.mountDone[blockstorage_t blockId](storage_result_t result, volume_id_t id) {
    signal Mount.mountDone[blockId](result, id);
  }

  default event void Mount.mountDone[blockstorage_t blockId](storage_result_t result, volume_id_t id) {
  }
}

--- NEW FILE: ByteEEPROM.nc ---
// $Id: ByteEEPROM.nc,v 1.1 2005/07/11 23:36:08 idgay Exp $

/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */
/*
 * Authors:		Nelson Lee, David Gay
 * Date last modified:  7/17/03
 */
/**
 * Provide access to, and sharing of, the mote flash
 * chip. <code>ByteEEPROM</code> does not interact properly with the
 * (deprecated) <code>Logger</code> component.
 *
 * The flash chip is shared by giving each user a separate "region" of the
 * flash. These regions are identified by the parameter to the
 * <code>AllocationReq</code>, <code>WriteData</code>,
 * <code>ReadData</code> and <code>LogData</code> parameterised
 * interfaces. A user of byte eeprom should define a constant with 
 * enum { MY_FLASH_REGION_ID = unique("ByteEEPROM") }; 
 * in some .h file, and use <code>MY_FLASH_REGION_ID</code> when wiring
 * interfaces to <code>ByteEEPROM</code>.
 *
 * Flash regions must be allocated via the <code>AllocationReq</code>
 * interface.  All allocation requests must be made at mote initialisation
 * time (in <code>StdControl.init</code> commands). Later allocation
 * requests will be refused.
 *
 * <code>ReadData</code> and <code>WriteData</code> provides
 * straightforward data reading and writing at arbitrary offsets in a flash
 * region. The <code>WriteData</code> interface guarantees that the data
 * has been committed to the flash when the <code>writeDone</code> event
 * completes successfully. As this has high overhead (both in time and
 * power), the alternative <code>LogData</code> interface is provided for
 * high-speed, low-overhead data logging.
 *
 * The <code>BufferedLog</code> component can be used in conjunction with
 * <code>ByteEEPROM</code> to provide even lower logging overhead at the cost
 * of extra RAM buffers. The <code>HighFrequencySampling</code> application
 * is an example of all this.
 * @author Nelson Lee
 * @author David Gay
 */
configuration ByteEEPROM {
  provides {
    interface AllocationReq[uint8_t id];
    interface WriteData[uint8_t id];
    interface LogData[uint8_t id];
    interface ReadData[uint8_t id];
    interface StdControl;
  }
}
implementation {
  components PageEEPROMC, ByteEEPROMC, ByteEEPROMAllocate;

  AllocationReq = ByteEEPROMAllocate;
  WriteData = ByteEEPROMC;
  LogData = ByteEEPROMC;
  ReadData = ByteEEPROMC;
  StdControl = ByteEEPROMAllocate;
  StdControl = PageEEPROMC;
  
  ByteEEPROMC.PageEEPROM -> PageEEPROMC.PageEEPROM[unique("PageEEPROM")];
  ByteEEPROMC.getRegion -> ByteEEPROMAllocate;
}










--- NEW FILE: ByteEEPROMC.nc ---
// $Id: ByteEEPROMC.nc,v 1.1 2005/07/11 23:36:08 idgay Exp $

/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */



/*
  --Initialization--
  Each app that uses ByteEEPROM should call init() before Request
  or RequestAddr.  It is safe to call init multiple times.

  --Start--
  Each app that uses ByteEEPROM should call start() in its own
  start method. It is safe to call start multiple times.

  --Interface Wiring--
  apps that use this component should wire specific instances of AllocationReq,
  SendDataToMapped, and ReadDataToMapped. The reason for having these interfaces
  parameterized is so ByteEEPROM can communicate with each app separately.
  For example, when an app requests a read, when the read completes, this ByteEEPROM
  can then signal a readDone to only the application that requested it; similar is the
  case for writes.

  --Notes--
  TOS_EEPROM_MAX_LINES = 0x80000 >> TOS_EEPROM_LOG2_LINE_SIZE is the maximum number of
  lines. Therefore, (TOS_EEPROM_MAX_LINES - 1) << TOS_EEPROM_LOG2_LINE_SIZE is the last
  line/page that can be requested.
  
*/

includes ByteEEPROMInternal;
module ByteEEPROMC {
  provides {
    interface WriteData[uint8_t id];
    interface LogData[uint8_t id];
    interface ReadData[uint8_t id];
  }
  uses {
    command RegionSpecifier *getRegion(uint8_t id);
    interface PageEEPROM;
    interface Leds;
  }
}
implementation {
  enum {
    S_IDLE,
    S_READ,
    S_WRITE,
    S_APPEND,
    S_SYNC,
    S_ERASE
  };

  uint8_t state;
  
  uint8_t appID;
  uint32_t startAddr;
  uint32_t stopAddr;
  uint32_t numBytes;
  uint32_t dataBufferOffset;
  uint8_t *dataBuffer;
  bool writesLastByte;

  enum {
    NREGIONS = uniqueCount("ByteEEPROM"),
    PAGE_SIZE = 1 << TOS_EEPROM_PAGE_SIZE_LOG2,
    PAGE_SIZE_MASK = PAGE_SIZE - 1
  };

  // appendOffsets for the regions. They are stored as "real offset"+1 to
  // provide easy handling of the "append offset" invalid condition
  uint32_t appendOffset[NREGIONS];

  RegionSpecifier *newRequest(uint8_t clientId) {
    if (S_IDLE != state)
      return NULL;

    appID = clientId;

    return call getRegion(clientId);
  }
  
  result_t newBufferRequest(uint8_t clientId, uint32_t offset,
			    uint8_t *buffer, uint32_t count) {
    RegionSpecifier *mappedRegion = newRequest(clientId);
    
    if (mappedRegion == NULL)
      return FAIL;
    
    // the first byte actually read from
    startAddr = mappedRegion->startByte + offset;
    // the byte addr before stopAddr is the last byte we actually read
    stopAddr = mappedRegion->startByte + offset + count;

    //offset out of range, or trying to read too many bytes
    if ((startAddr < mappedRegion->startByte) ||
	(startAddr >= mappedRegion->stopByte))
      return FAIL;
    if ((stopAddr <= mappedRegion->startByte) ||
	(stopAddr > mappedRegion->stopByte))
      return FAIL;

    // We note if we're writing the last byte (append needs to know this to
    // avoid erasing the first page of the next region)
    writesLastByte = stopAddr == mappedRegion->stopByte;
    
    // Save the request data in our state vars
    numBytes = count;
    dataBuffer = buffer;
    dataBufferOffset = 0;

    return SUCCESS;
  }
  
  void completeOp(result_t success) {
    uint8_t op = state;

    state = S_IDLE;
    switch (op)
      {
      case S_READ:
	signal ReadData.readDone[appID](dataBuffer, numBytes, success);
	break;
      case S_WRITE:
	signal WriteData.writeDone[appID](dataBuffer, numBytes, success);
	break;
      case S_APPEND:
	if (success)
	  appendOffset[appID] += numBytes;
	signal LogData.appendDone[appID](dataBuffer, numBytes, success);
	break;
      case S_SYNC:
	signal LogData.syncDone[appID](success); 
	break;
      case S_ERASE:
	signal LogData.eraseDone[appID](success); 
	break;
      }
  }

  task void successTask() {
    completeOp(SUCCESS);
  }

  task void failTask() {
    completeOp(FAIL);
  }

  void check(result_t success) {
    if (!success)
      post failTask();
  }

  void continueOp() {
    eeprompage_t sPage = startAddr >> TOS_EEPROM_PAGE_SIZE_LOG2;
    eeprompage_t ePage = stopAddr >> TOS_EEPROM_PAGE_SIZE_LOG2;
    eeprompageoffset_t offset, count;

    if (startAddr == stopAddr)
      {
	post successTask();
	return;
      }

    offset = startAddr & PAGE_SIZE_MASK;
    if (sPage == ePage)
      count = stopAddr - startAddr;
    else
      count = PAGE_SIZE - offset;

    switch (state)
      {
      case S_READ:
	check(call PageEEPROM.read(sPage, offset, dataBuffer + dataBufferOffset, count));
	break;
      case S_WRITE:  case S_APPEND:
	check(call PageEEPROM.write(sPage, offset, dataBuffer + dataBufferOffset, count));
	break;
      }

    dataBufferOffset += count;
    startAddr += count;
  }

  event result_t PageEEPROM.readDone(result_t success) {
    if (success == FAIL)
      completeOp(FAIL);
    else 
      continueOp();
    return SUCCESS;
  }

  event result_t PageEEPROM.writeDone(result_t success) {
    if (success == FAIL)
      completeOp(FAIL);
    else 
      {
	if (state == S_APPEND && (startAddr & PAGE_SIZE_MASK) == 0 &&
	    !(writesLastByte && startAddr == stopAddr))
	  /* If an appending write filled the page, flush the last page and
	     remind the EEPROM that the next page has been erased.
	     Semi-hack: if this append is writing the last byte of a region
	     whose size is the multiple of the page size, we don't want to
	     erase the next page (as it belongs to another region). We
	     detect this with the writesLastByte boolean... */
	  check(call PageEEPROM.flush((startAddr >> TOS_EEPROM_PAGE_SIZE_LOG2) - 1));
	else
	  continueOp();
      }
    return SUCCESS;
  }

  event result_t PageEEPROM.flushDone(result_t result) {
    check(call PageEEPROM.erase(startAddr >> TOS_EEPROM_PAGE_SIZE_LOG2,
				TOS_EEPROM_PREVIOUSLY_ERASED));
    return SUCCESS;
  }

  command result_t ReadData.read[uint8_t id](uint32_t offset, uint8_t *buffer, uint32_t numBytesRead) {
    if (newBufferRequest(id, offset, buffer, numBytesRead) == FAIL)
      return FAIL;

    state = S_READ;
    continueOp();

    return SUCCESS;
  }
  
  command result_t WriteData.write[uint8_t id](uint32_t offset, uint8_t *buffer, uint32_t numBytesWrite) {
    if (newBufferRequest(id, offset, buffer, numBytesWrite) == FAIL)
      return FAIL;

    state = S_WRITE;
    continueOp();

    return SUCCESS;
  }
  
  command result_t LogData.append[uint8_t id](uint8_t *buffer, uint32_t numBytesWrite) {
    // The use of appendOffset - 1 will make newBufferRequest fail if
    // appends are not currently allowed
    if (newBufferRequest(id, appendOffset[id] - 1, buffer, numBytesWrite) == FAIL)
      return FAIL;

    state = S_APPEND;
    continueOp();

    return SUCCESS;
  }

  command uint32_t LogData.currentOffset[uint8_t id]() {
    if (call getRegion(id))
      return appendOffset[id] - 1;
    else
      return (uint32_t)-1;
  }
  
  command result_t LogData.sync[uint8_t clientId]() {
    if (!newRequest(clientId))
      return FAIL;
    appendOffset[clientId] = 0; // disable append
    state = S_SYNC;
    check(call PageEEPROM.syncAll());
    return SUCCESS;
  }

  event result_t PageEEPROM.syncDone(result_t result) { 
    completeOp(result);
    return SUCCESS;
  }

  command result_t LogData.erase[uint8_t clientId]() {
    RegionSpecifier *mappedRegion = newRequest(clientId);

    if (!mappedRegion)
      return FAIL;

    /* We erase backwards so that the first page (where we will start
       appending) is in the cache in an "erased" state */
    state = S_ERASE;
    startAddr = mappedRegion->startByte >> TOS_EEPROM_PAGE_SIZE_LOG2;
    stopAddr = (mappedRegion->stopByte - 1) >> TOS_EEPROM_PAGE_SIZE_LOG2;
    appendOffset[clientId] = 1; // start appending at offset 0

    check(call PageEEPROM.erase(stopAddr, TOS_EEPROM_ERASE));

    return SUCCESS;
  }

  event result_t PageEEPROM.eraseDone(result_t success) {
    if (!success)
      completeOp(success);
    else if (state == S_APPEND)
      continueOp();
    else
      {
	if (startAddr == stopAddr)
	  completeOp(SUCCESS);
	else
	  {
	    stopAddr--;
	    check(call PageEEPROM.erase(stopAddr, TOS_EEPROM_ERASE));
	  }
      }
    return SUCCESS;
  }
  
  default event result_t WriteData.writeDone[uint8_t id](uint8_t *data, uint32_t numBytesWrite, result_t success) {
    return SUCCESS;
  }

  default event result_t ReadData.readDone[uint8_t id](uint8_t *buffer, uint32_t numBytesRead, result_t success) {
    return SUCCESS;
  }

  default event result_t LogData.appendDone[uint8_t id](uint8_t *data, uint32_t numBytesWrite, result_t success) {
    return SUCCESS;
  }

  default event result_t LogData.eraseDone[uint8_t id](result_t success) {
    return SUCCESS;
  }

  default event result_t LogData.syncDone[uint8_t id](result_t success) {
    return SUCCESS;
  }

  event result_t PageEEPROM.computeCrcDone(result_t result, uint16_t crc) {
    return SUCCESS;
  }
}

--- NEW FILE: FormatStorageC.nc ---
// $Id: FormatStorageC.nc,v 1.1 2005/07/11 23:36:08 idgay Exp $

/*									tab:2
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 */

/*
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 * @author David Gay
 */

includes crc;
includes Storage;
#define HALAT45DB PageEEPROM

configuration FormatStorageC {
  provides interface FormatStorage;
}
implementation {
  components FormatStorageM, Main, PageEEPROMC as HALAT45DBC;

  FormatStorage = FormatStorageM;

  Main.StdControl -> FormatStorageM;
  Main.StdControl -> HALAT45DBC;
  FormatStorageM.HALAT45DB -> HALAT45DBC.HALAT45DB[unique("PageEEPROM")];
}

--- NEW FILE: FormatStorageM.nc ---
// $Id: FormatStorageM.nc,v 1.1 2005/07/11 23:36:08 idgay Exp $

/*									tab:2
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 */

/*
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 * @author David Gay
 */

includes Storage;
#define HALAT45DB PageEEPROM
includes StorageManager;
includes crc;

module FormatStorageM {
  provides {
    interface FormatStorage;
    interface StdControl;
  }
  uses {
    interface HALAT45DB;
  }
}
implementation {
  struct volume_definition_header_t header;
  struct volume_definition_t volumes[MAX_VOLUMES];

  uint8_t state;

  enum {
    S_INIT,
    S_COMMIT, S_COMMIT_HEADER, S_COMMIT_VOLUMES, S_COMMIT_DONE
  };
  
  void signalDone(storage_result_t result) {
    state = S_COMMIT_DONE;
    signal FormatStorage.commitDone(result);
  }

  command result_t StdControl.init() {
    state = S_COMMIT_DONE;
    return SUCCESS;
  }

  command result_t StdControl.start() {
    return SUCCESS;
  }

  command result_t StdControl.stop() {
    return SUCCESS;
  }

  command result_t FormatStorage.init() {
    header.nvolumes = 0;
    state = S_INIT;

    return SUCCESS;
  }

  bool checkNewVolume(volume_id_t id, storage_addr_t addr, storage_addr_t size) {
    volume_id_t i;

    if (state != S_INIT)
      return FALSE;

    if (addr & ((1 << AT45_PAGE_SIZE_LOG2) - 1))
      return FALSE;

    // size must be a multiple of sector size
    if (size & ((1 << AT45_PAGE_SIZE_LOG2) - 1))
      return FALSE;

    // check if id is already taken
    for (i = 0; i < header.nvolumes; i++)
      if (volumes[i].id == id)
	return FALSE;

    return TRUE;
  }

  bool pageWithin(at45page_t page, at45page_t s, at45page_t len) {
    // page - s < len rather page < s + len to avoid overflow
    return page >= s && page - s < len;
  }

  result_t newVolume(uint8_t i, volume_id_t id, at45page_t start, at45page_t length) {
    if (start >= AT45_MAX_PAGES || length > AT45_MAX_PAGES - start)
      return FAIL;

    volumes[i].start = start;
    volumes[i].length = length;
    volumes[i].id = id;
    header.nvolumes++;

    return SUCCESS;
  }

  command result_t FormatStorage.allocate(volume_id_t id, storage_addr_t size) {
    at45page_t addr;
    uint8_t i;

    if (!checkNewVolume(id, 0, size))
      return FAIL;

    size >>= AT45_PAGE_SIZE_LOG2;

    /* First fit. */
    addr = 0;
    for (i = 0; i < header.nvolumes; i++)
      if (addr < volumes[i].start && size < volumes[i].start - addr)
	{
	  memmove(&volumes[i + 1], &volumes[i],
		  (header.nvolumes - i) * sizeof(volumes[i]));
	  break;
	}
      else
	addr = volumes[i].start + volumes[i].length;

    return newVolume(i, id, addr, size);
  }

  command result_t FormatStorage.allocateFixed(volume_id_t id, storage_addr_t addr, storage_addr_t size) {
    uint8_t i;

    if (!checkNewVolume(id, addr, size))
      return FAIL;

    addr >>= AT45_PAGE_SIZE_LOG2;
    size >>= AT45_PAGE_SIZE_LOG2;

    // Check if overlaps any existing allocation
    for (i = 0; i < header.nvolumes; i++)
      if (pageWithin(addr, volumes[i].start, volumes[i].length) ||
	  pageWithin(addr + size - 1, volumes[i].start, volumes[i].length) ||
	  pageWithin(volumes[i].start, addr, size) ||
	  pageWithin(volumes[i].start + volumes[i].length - 1, addr, size))
	return FAIL;

    // Insert at correct position.  These last two loops could be merged,
    // if there was any reason to care about performance
    for (i = 0; i < header.nvolumes; i++)
      if (addr < volumes[i].start)
	{
	  memmove(&volumes[i + 1], &volumes[i],
		  (header.nvolumes - i) * sizeof(volumes[i]));
	  break;
	}

    return newVolume(i, id, addr, size);
  }
   
  uint16_t computeSectorTableCrc() {
    uint16_t crc;
    unsigned char *vtable = (unsigned char *)volumes;
    size_t nvOffset = offsetof(struct volume_definition_header_t, nvolumes);
    size_t i;

    crc = 0;
    /* There may be padding after nvolumes, hence this loop */
    for (i = nvOffset; i < sizeof header; i++)
      crc = crcByte(crc, ((unsigned char *)&header)[i]);
    for (i = 0; i < header.nvolumes * sizeof *volumes; i++)
      crc = crcByte(crc, vtable[i]);

    return crc;
  }

  void commitComplete(result_t x) {
    state = S_COMMIT_DONE;
    signal FormatStorage.commitDone(x == FAIL ? STORAGE_FAIL : STORAGE_OK);
  }

  task void commitVolumes() {
    header.crc = computeSectorTableCrc();
    if (call HALAT45DB.write(VOLUME_TABLE_PAGE, 0, &header, sizeof header) != FAIL)
      state = S_COMMIT_HEADER;
    else
      commitComplete(FAIL);
  }

  event result_t HALAT45DB.writeDone(result_t result) {
    if (result != FAIL)
      switch (state)
	{
	case S_COMMIT_HEADER:
	  result = call HALAT45DB.write(VOLUME_TABLE_PAGE, sizeof header, &volumes,
					sizeof *volumes * header.nvolumes);
	  state = S_COMMIT_VOLUMES;
	  break;
	case S_COMMIT_VOLUMES:
	  result = call HALAT45DB.sync(VOLUME_TABLE_PAGE);
	}
    if (result == FAIL)
      commitComplete(FAIL);
    return SUCCESS;
  }

  event result_t HALAT45DB.syncDone(result_t result) {
    commitComplete(result);
    return SUCCESS;
  }

  event result_t HALAT45DB.eraseDone(result_t result) {
    return SUCCESS;
  }

  event result_t HALAT45DB.flushDone(result_t result) {
    return SUCCESS;
  }

  event result_t HALAT45DB.readDone(result_t result) {
    return SUCCESS;
  }

  event result_t HALAT45DB.computeCrcDone(result_t result, uint16_t crc) {
    return SUCCESS;
  }

  command result_t FormatStorage.commit() {
    if (state != S_INIT)
      return FAIL;

    state = S_COMMIT;

    post commitVolumes();

    return SUCCESS;
  }
}

--- NEW FILE: HALAT45DB.h ---
#ifndef AT45COMPAT_H
#define AT45COMPAT_H

/* Make the 1.x interfaces appear like the 2.x AT45DB HAL */

#include "PageEEPROM.h"

typedef eeprompage_t at45page_t;
typedef eeprompageoffset_t at45pageoffset_t;

enum {
  AT45_MAX_PAGES = TOS_EEPROM_MAX_PAGES,
  AT45_PAGE_SIZE = TOS_EEPROM_PAGE_SIZE,
  AT45_PAGE_SIZE_LOG2 = TOS_EEPROM_PAGE_SIZE_LOG2,
  AT45_ERASE = TOS_EEPROM_ERASE,
  AT45_DONT_ERASE = TOS_EEPROM_DONT_ERASE,
  AT45_PREVIOUSLY_ERASED = TOS_EEPROM_PREVIOUSLY_ERASED
};

#endif

--- NEW FILE: HALAT45DBShare.nc ---
// $Id: HALAT45DBShare.nc,v 1.1 2005/07/11 23:36:08 idgay Exp $

/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */
/**
 * Provide simple multi-client access to HALAT45DB volumes:
 * - does request-response matching (per-volume), i.e., you only get events
 *   for commands on the volume you're using (normally only one user per
 *   volume)
 * - does page remapping so you can use volume-relative page numbers
 */

includes Storage;
#define HALAT45DB PageEEPROM

module HALAT45DBShare {
  provides interface HALAT45DB[volume_t volume];
  uses interface HALAT45DB as ActualAT45;
  uses interface AT45Remap;
}
implementation {
  volume_t lastClient;

  int setClient(volume_t client) {
    if (lastClient)
      return FALSE;
    lastClient = client + 1;

    return TRUE;
  }

  volume_t getClient() {
    volume_t id = lastClient - 1;

    lastClient = 0;

    return id;
  }

  inline at45page_t remap(at45page_t page) {
    return call AT45Remap.remap(lastClient - 1, page);
  }

  /* Clear client if request failed. */
  result_t check(result_t requestOk) {
    if (requestOk != FAIL)
      return requestOk;
    lastClient = 0;
    return FAIL;
  }

  // Simply use the setClient, getClient functions to match requests &
  // responses. The inline reduces the overhead of this layer.
  inline command result_t HALAT45DB.write[volume_t client](at45page_t page, at45pageoffset_t offset,
							   void *data, at45pageoffset_t n) {
    if (!setClient(client))
      return FAIL;
    return check(call ActualAT45.write(remap(page), offset, data, n));
  }

  inline event result_t ActualAT45.writeDone(result_t result) {
    return signal HALAT45DB.writeDone[getClient()](result);
  }

  inline command result_t HALAT45DB.erase[volume_t client](at45page_t page, uint8_t eraseKind) {
    if (!setClient(client))
      return FAIL;
    return check(call ActualAT45.erase(remap(page), eraseKind));
  }

  inline event result_t ActualAT45.eraseDone(result_t result) {
    return signal HALAT45DB.eraseDone[getClient()](result);
  }

  inline command result_t HALAT45DB.sync[volume_t client](at45page_t page) {
    if (!setClient(client))
      return FAIL;
    return check(call ActualAT45.sync(page));
  }

  inline command result_t HALAT45DB.syncAll[volume_t client]() {
    if (!setClient(client))
      return FAIL;
    return check(call ActualAT45.syncAll());
  }

  inline event result_t ActualAT45.syncDone(result_t result) {
    return signal HALAT45DB.syncDone[getClient()](result);
  }

  inline command result_t HALAT45DB.flush[volume_t client](at45page_t page) {
    if (!setClient(client))
      return FAIL;
    return check(call ActualAT45.flush(remap(page)));
  }

  inline command result_t HALAT45DB.flushAll[volume_t client]() {
    if (!setClient(client))
      return FAIL;
    return check(call ActualAT45.flushAll());
  }

  inline event result_t ActualAT45.flushDone(result_t result) {
    return signal HALAT45DB.flushDone[getClient()](result);
  }

  inline command result_t HALAT45DB.read[volume_t client](at45page_t page, at45pageoffset_t offset,
							  void *data, at45pageoffset_t n) {
    if (!setClient(client))
      return FAIL;
    return check(call ActualAT45.read(remap(page), offset, data, n));
  }

  inline event result_t ActualAT45.readDone(result_t result) {
    return signal HALAT45DB.readDone[getClient()](result);
  }

  inline command result_t HALAT45DB.computeCrc[volume_t client](at45page_t page, at45pageoffset_t offset,
								at45pageoffset_t n) {
    if (!setClient(client))
      return FAIL;
    return check(call ActualAT45.computeCrc(remap(page), offset, n));
  }

  inline event result_t ActualAT45.computeCrcDone(result_t result, uint16_t crc) {
    return signal HALAT45DB.computeCrcDone[getClient()](result, crc);
  }
  
  default event result_t HALAT45DB.writeDone[volume_t client](result_t result) {
    return FAIL;
  }

  default event result_t HALAT45DB.eraseDone[volume_t client](result_t result) {
    return FAIL;
  }

  default event result_t HALAT45DB.syncDone[volume_t client](result_t result) {
    return FAIL;
  }

  default event result_t HALAT45DB.flushDone[volume_t client](result_t result) {
    return FAIL;
  }

  default event result_t HALAT45DB.readDone[volume_t client](result_t result) {
    return FAIL;
  }

  default event result_t HALAT45DB.computeCrcDone[volume_t client](result_t result, uint16_t crc) {
    return FAIL;
  }
}

--- NEW FILE: PageEEPROM.h ---
// $Id: PageEEPROM.h,v 1.1 2005/07/11 23:36:08 idgay Exp $

/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */
#ifndef TOS_PAGEEEPROM_H
#define TOS_PAGEEEPROM_H

#include <PageEEPROM_platform.h>

enum {
  TOS_EEPROM_ERASE,
  TOS_EEPROM_DONT_ERASE,
  TOS_EEPROM_PREVIOUSLY_ERASED
};

#endif

--- NEW FILE: PageEEPROM.nc ---
// $Id: PageEEPROM.nc,v 1.1 2005/07/11 23:36:08 idgay Exp $

/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */
includes PageEEPROM;
interface PageEEPROM {
  command result_t write(eeprompage_t page, eeprompageoffset_t offset,
			 void *data, eeprompageoffset_t n);
  event result_t writeDone(result_t result);

  command result_t erase(eeprompage_t page, uint8_t eraseKind);
  event result_t eraseDone(result_t result);

  command result_t sync(eeprompage_t page);
  command result_t syncAll();
  event result_t syncDone(result_t result);

  command result_t flush(eeprompage_t page);
  command result_t flushAll();
  event result_t flushDone(result_t result);

  command result_t read(eeprompage_t page, eeprompageoffset_t offset,
			void *data, eeprompageoffset_t n);
  event result_t readDone(result_t result);

  command result_t computeCrc(eeprompage_t page, eeprompageoffset_t offset,
			      eeprompageoffset_t n);
  event result_t computeCrcDone(result_t result, uint16_t crc);
}

--- NEW FILE: PageEEPROMShare.nc ---
// $Id: PageEEPROMShare.nc,v 1.1 2005/07/11 23:36:08 idgay Exp $

/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */
/**
 * Provide simple multi-client access to a PageEEPROM interface
 * (just request-response matching)
 */
module PageEEPROMShare {
  provides interface PageEEPROM[uint8_t id];
  uses interface PageEEPROM as ActualEEPROM;
}
implementation {
  enum {
    NCLIENTS = uniqueCount("PageEEPROM")
  };
  uint8_t lastClient;

  // Read & write the client id. We special case the 1-client case to
  // eliminate the overhead (still costs 1 byte of ram, though)
  int setClient(uint8_t client) {
    if (NCLIENTS != 1)
      {
	if (lastClient)
	  return FALSE;
	lastClient = client + 1;
      }
    return TRUE;
  }

  uint8_t getClient() {
    uint8_t id = 0;

    if (NCLIENTS != 1)
      {
	id = lastClient - 1;
	lastClient = 0;
      }

    return id;
  }

  /* Clear client if request failed. */
  result_t check(result_t requestOk) {
    if (requestOk != FAIL)
      return requestOk;
    lastClient = 0;
    return FAIL;
  }

  // Simply use the setClient, getClient functions to match requests &
  // responses. The inline reduces the overhead of this layer.
  inline command result_t PageEEPROM.write[uint8_t client](eeprompage_t page, eeprompageoffset_t offset,
						    void *data, eeprompageoffset_t n) {
    if (!setClient(client))
      return FAIL;
    return check(call ActualEEPROM.write(page, offset, data, n));
  }

  inline event result_t ActualEEPROM.writeDone(result_t result) {
    return signal PageEEPROM.writeDone[getClient()](result);
  }

  inline command result_t PageEEPROM.erase[uint8_t client](eeprompage_t page, uint8_t eraseKind) {
    if (!setClient(client))
      return FAIL;
    return check(call ActualEEPROM.erase(page, eraseKind));
  }

  inline event result_t ActualEEPROM.eraseDone(result_t result) {
    return signal PageEEPROM.eraseDone[getClient()](result);
  }

  inline command result_t PageEEPROM.sync[uint8_t client](eeprompage_t page) {
    if (!setClient(client))
      return FAIL;
    return check(call ActualEEPROM.sync(page));
  }

  inline command result_t PageEEPROM.syncAll[uint8_t client]() {
    if (!setClient(client))
      return FAIL;
    return check(call ActualEEPROM.syncAll());
  }

  inline event result_t ActualEEPROM.syncDone(result_t result) {
    return signal PageEEPROM.syncDone[getClient()](result);
  }

  inline command result_t PageEEPROM.flush[uint8_t client](eeprompage_t page) {
    if (!setClient(client))
      return FAIL;
    return check(call ActualEEPROM.flush(page));
  }

  inline command result_t PageEEPROM.flushAll[uint8_t client]() {
    if (!setClient(client))
      return FAIL;
    return check(call ActualEEPROM.flushAll());
  }

  inline event result_t ActualEEPROM.flushDone(result_t result) {
    return signal PageEEPROM.flushDone[getClient()](result);
  }

  inline command result_t PageEEPROM.read[uint8_t client](eeprompage_t page, eeprompageoffset_t offset,
						   void *data, eeprompageoffset_t n) {
    if (!setClient(client))
      return FAIL;
    return check(call ActualEEPROM.read(page, offset, data, n));
  }

  inline event result_t ActualEEPROM.readDone(result_t result) {
    return signal PageEEPROM.readDone[getClient()](result);
  }

  inline command result_t PageEEPROM.computeCrc[uint8_t client](eeprompage_t page, eeprompageoffset_t offset,
							 eeprompageoffset_t n) {
    if (!setClient(client))
      return FAIL;
    return check(call ActualEEPROM.computeCrc(page, offset, n));
  }

  inline event result_t ActualEEPROM.computeCrcDone(result_t result, uint16_t crc) {
    return signal PageEEPROM.computeCrcDone[getClient()](result, crc);
  }
  
  default event result_t PageEEPROM.writeDone[uint8_t client](result_t result) {
    return FAIL;
  }

  default event result_t PageEEPROM.eraseDone[uint8_t client](result_t result) {
    return FAIL;
  }

  default event result_t PageEEPROM.syncDone[uint8_t client](result_t result) {
    return FAIL;
  }

  default event result_t PageEEPROM.flushDone[uint8_t client](result_t result) {
    return FAIL;
  }

  default event result_t PageEEPROM.readDone[uint8_t client](result_t result) {
    return FAIL;
  }

  default event result_t PageEEPROM.computeCrcDone[uint8_t client](result_t result, uint16_t crc) {
    return FAIL;
  }
}

--- NEW FILE: StorageManager.h ---
#ifndef STORAGE_MANAGER_H
#define STORAGE_MANAGER_H

struct volume_definition_header_t
{
  uint16_t crc;
  uint8_t nvolumes;
};

struct volume_definition_t
{
  volume_id_t id;
  at45page_t start, length;
};

enum {
  INVALID_VOLUME_ID = 0,
  VOLUME_TABLE_SIZE = AT45_PAGE_SIZE,
  VOLUME_TABLE_PAGE = AT45_MAX_PAGES - 1,
  MAX_VOLUMES = (VOLUME_TABLE_SIZE - sizeof(struct volume_definition_header_t)) / sizeof(struct volume_definition_t)
};

#endif

--- NEW FILE: StorageManagerC.nc ---
includes Storage;
#define HALAT45DB PageEEPROM
includes BlockStorage;

configuration StorageManagerC {
  provides {
    interface StdControl;
    interface Mount[volume_t volume];
    interface HALAT45DB[volume_t volume];
    interface AT45Remap;
  }
}
implementation {
  components StorageManagerM, PageEEPROMC as HALAT45DBC, HALAT45DBShare, InternalFlashC;

  StdControl = StorageManagerM;
  StdControl = HALAT45DBC;
  Mount = StorageManagerM;
  HALAT45DB = HALAT45DBShare;
  AT45Remap = StorageManagerM;

  StorageManagerM.HALAT45DB -> HALAT45DBShare.HALAT45DB[uniqueCount("StorageManager")];

  HALAT45DBShare.ActualAT45 -> HALAT45DBC.PageEEPROM[unique("PageEEPROM")];
  HALAT45DBShare.AT45Remap -> StorageManagerM;
}

--- NEW FILE: StorageManagerM.nc ---
includes crc;
includes StorageManager;
#define HALAT45DB PageEEPROM
module StorageManagerM {
  provides {
    interface StdControl;
    interface Mount[volume_t volume];
    interface AT45Remap;
  }
  uses interface HALAT45DB;
}
implementation {
  enum {
    NVOLUMES = uniqueCount("StorageManager")
  };

  struct volume_definition_header_t header;
  struct volume_definition_t volumes[NVOLUMES];

  enum {
    S_READY,
    S_MOUNTING
  };
  struct {
    bool validated : 1;
    bool invalid : 1;
    bool busy : 1;
    uint8_t state : 2;
  } f;

  uint8_t nextVolume;
  volume_t client;
  volume_id_t id;

  command result_t StdControl.init() {
    uint8_t i;

    for (i = 0; i < NVOLUMES; i++)
      volumes[i].id = INVALID_VOLUME_ID;

    return SUCCESS;
  }

  command result_t StdControl.start() {
    return SUCCESS;
  }

  command result_t StdControl.stop() {
    return SUCCESS;
  }

  void mountComplete(storage_result_t r) {
    f.busy = FALSE;
    signal Mount.mountDone[client](r, id);
  }

  void check(result_t r) {
    if (r == FAIL)
      mountComplete(STORAGE_FAIL);
  }

  void checkNextVolume() {
    if (f.invalid || nextVolume == header.nvolumes)
      {
	volumes[client].id = INVALID_VOLUME_ID;
	mountComplete(STORAGE_FAIL);
      }
    else
      check(call HALAT45DB.read(VOLUME_TABLE_PAGE, sizeof(struct volume_definition_header_t) +
				nextVolume++ * sizeof(struct volume_definition_t),
				&volumes[client], sizeof volumes[client]));
  }

  task void mountVolume() {
    if (!f.validated)
      check(call HALAT45DB.read(VOLUME_TABLE_PAGE, 0, &header, sizeof header));
    else
      checkNextVolume();
  }

  command result_t Mount.mount[volume_t v](volume_id_t i) {
    if (f.busy || volumes[v].id != INVALID_VOLUME_ID)
      return FAIL;

    f.busy = TRUE;
    client = v;
    id = i;
    nextVolume = 0;
    post mountVolume();

    return SUCCESS;
  }

  command at45page_t AT45Remap.remap(volume_t volume, at45page_t volumePage) {
    if (volume == NVOLUMES) // special internal-use case
      return volumePage;
    else
      return volumePage + volumes[volume].start;
  }

  command storage_addr_t AT45Remap.volumeSize(volume_t volume) {
    return (storage_addr_t)volumes[volume].length << AT45_PAGE_SIZE_LOG2;
  }

  event result_t HALAT45DB.writeDone(result_t result) {
    return SUCCESS;
  }

  event result_t HALAT45DB.eraseDone(result_t result) {
    return SUCCESS;
  }

  event result_t HALAT45DB.syncDone(result_t result) {
    return SUCCESS;
  }

  event result_t HALAT45DB.flushDone(result_t result) {
    return SUCCESS;
  }

  event result_t HALAT45DB.readDone(result_t result) {
    if (!f.validated)
      {
	size_t nvOffset = offsetof(struct volume_definition_header_t, nvolumes);
	size_t n = header.nvolumes * sizeof *volumes +
	  sizeof(struct volume_definition_header_t) - nvOffset;

	check(call HALAT45DB.computeCrc(VOLUME_TABLE_PAGE, nvOffset, n));
      }
    else
      {
	if (volumes[client].id == id)
	  mountComplete(STORAGE_OK);
	else
	  checkNextVolume();
      }
    return SUCCESS;
  }

  event result_t HALAT45DB.computeCrcDone(result_t result, uint16_t crc) {
    f.validated = TRUE;
    f.invalid = crc != header.crc;
    checkNextVolume();
    return SUCCESS;
  }
}

--- NEW FILE: Storage_chip.h ---
#include "HALAT45DB.h"

typedef uint32_t storage_addr_t;



More information about the Tinyos-commits mailing list