[Tinyos-beta-commits] CVS: tinyos-1.x/beta/STM25P/STM25P BlockRead.nc, NONE, 1.1 BlockStorage.h, NONE, 1.1 BlockStorageC.nc, NONE, 1.1 BlockStorageM.nc, NONE, 1.1 BlockWrite.nc, NONE, 1.1 FlashWP.nc, NONE, 1.1 FlashWPC.nc, NONE, 1.1 FlashWPM.nc, NONE, 1.1 FormatStorage.nc, NONE, 1.1 FormatStorageC.nc, NONE, 1.1 FormatStorageM.nc, NONE, 1.1 HALSTM25P.h, NONE, 1.1 HALSTM25P.nc, NONE, 1.1 HALSTM25PC.nc, NONE, 1.1 HALSTM25PM.nc, NONE, 1.1 HPLSTM25P.nc, NONE, 1.1 LogRead.nc, NONE, 1.1 LogStorage.h, NONE, 1.1 LogStorageC.nc, NONE, 1.1 LogStorageM.nc, NONE, 1.1 LogWrite.nc, NONE, 1.1 Mount.nc, NONE, 1.1 SectorStorage.nc, NONE, 1.1 Storage.h, NONE, 1.1 StorageManager.nc, NONE, 1.1 StorageManagerC.nc, NONE, 1.1 StorageManagerM.nc, NONE, 1.1 StorageRemap.nc, NONE, 1.1 Storage_chip.h, NONE, 1.1

Jonathan Hui jwhui at users.sourceforge.net
Fri Mar 11 13:44:16 PST 2005


Update of /cvsroot/tinyos/tinyos-1.x/beta/STM25P/STM25P
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25492/STM25P

Added Files:
	BlockRead.nc BlockStorage.h BlockStorageC.nc BlockStorageM.nc 
	BlockWrite.nc FlashWP.nc FlashWPC.nc FlashWPM.nc 
	FormatStorage.nc FormatStorageC.nc FormatStorageM.nc 
	HALSTM25P.h HALSTM25P.nc HALSTM25PC.nc HALSTM25PM.nc 
	HPLSTM25P.nc LogRead.nc LogStorage.h LogStorageC.nc 
	LogStorageM.nc LogWrite.nc Mount.nc SectorStorage.nc Storage.h 
	StorageManager.nc StorageManagerC.nc StorageManagerM.nc 
	StorageRemap.nc Storage_chip.h 
Log Message:
- This directory contains the storage stack implementation for the
STM25P family of chips. The implementation follows proposed TinyOS
Storage Abstraction being introduced in TinyOS 2.x and detailed in
tep103.

- The new storage stack now requires formatting the flash before it
can be used. The flash is partitioned into segments with size equal to
a multiple of STORAGE_BLOCK_SIZE. An example for formating the flash
is included in beta/STM25P/TestStorage/.

- Implementation Status:
  - BlockStorage: nearly complete except commit()/verify(). Well
  tested under Deluge.
  - LogStorage: nearly complete except seek()/sync(). Limited testing.
  - ConfigStorage: not implemented



--- NEW FILE: BlockRead.nc ---
// $Id: BlockRead.nc,v 1.1 2005/03/11 21:43:59 jwhui Exp $

/*									tab:2
 * "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>
 */

includes BlockStorage;

interface BlockRead {

  command result_t read(block_addr_t addr, uint8_t* buf, block_addr_t len);
  event void readDone(storage_result_t result, block_addr_t addr, uint8_t* buf, block_addr_t len);

  command result_t verify();
  event void verifyDone(storage_result_t result);

  command result_t computeCrc(block_addr_t addr, block_addr_t len);
  event void computeCrcDone(storage_result_t result, uint16_t crc, block_addr_t addr, block_addr_t len);

}

--- NEW FILE: BlockStorage.h ---
// $Id: BlockStorage.h,v 1.1 2005/03/11 21:43:59 jwhui 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>
 */

#ifndef __BLOCK_STORAGE_H__
#define __BLOCK_STORAGE_H__

typedef uint32_t block_addr_t;
typedef uint8_t blockstorage_t;

#endif

--- NEW FILE: BlockStorageC.nc ---
// $Id: BlockStorageC.nc,v 1.1 2005/03/11 21:43:59 jwhui 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>
 */

includes BlockStorage;

configuration BlockStorageC {
  provides {
    interface Mount[blockstorage_t blockId];
    interface BlockRead[blockstorage_t blockId];
    interface BlockWrite[blockstorage_t blockId];
    interface StorageRemap[blockstorage_t blockId];
  }
}

implementation {

  components BlockStorageM, Main, StorageManagerC, LedsC as Leds;

  Mount = BlockStorageM.Mount;
  BlockRead = BlockStorageM.BlockRead;
  BlockWrite = BlockStorageM.BlockWrite;
  StorageRemap = StorageManagerC.StorageRemap;

  Main.StdControl -> StorageManagerC;

  BlockStorageM.SectorStorage -> StorageManagerC.SectorStorage;
  BlockStorageM.ActualMount -> StorageManagerC.Mount;
  BlockStorageM.StorageManager -> StorageManagerC.StorageManager;
  BlockStorageM.Leds -> Leds;

}

--- NEW FILE: BlockStorageM.nc ---
// $Id: BlockStorageM.nc,v 1.1 2005/03/11 21:43:59 jwhui 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>
 */

module BlockStorageM {
  provides {
    interface Mount[blockstorage_t blockId];
    interface BlockRead[blockstorage_t blockId];
    interface BlockWrite[blockstorage_t blockId];
  }
  uses {
    interface SectorStorage[blockstorage_t blockId];
    interface Leds;
    interface Mount as ActualMount[blockstorage_t blockId];
    interface StorageManager[blockstorage_t blockId];
  }
}

implementation {

  enum {
    S_IDLE,
    S_WRITE,
    S_ERASE,
    S_COMMIT,
    S_READ,
    S_VERIFY,
    S_CRC,
  };

  uint8_t state;
  uint8_t client;

  block_addr_t rwAddr, rwLen, curAddr;
  uint8_t* rwBuf;
  uint16_t crc;

  command result_t Mount.mount[blockstorage_t blockId](volume_id_t id) {
    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);
  }

  bool admitRequest(blockstorage_t blockId) {
    if (state != S_IDLE)
      return FALSE;
    client = blockId;
    return TRUE;
  }

  result_t check(result_t result) {
    if (result == FAIL) {
      state = S_IDLE;
      return FAIL;
    }
    return SUCCESS;
  }
  
  void signalDone(storage_result_t result) {
    uint8_t tmpState = state;
    state = S_IDLE;
    switch(tmpState) {
    case S_WRITE: signal BlockWrite.writeDone[client](result, rwAddr, rwBuf, rwLen); break;
    case S_ERASE: signal BlockWrite.eraseDone[client](result); break;
    case S_COMMIT: signal BlockWrite.commitDone[client](result); break;
    case S_READ: signal BlockRead.readDone[client](result, rwAddr, rwBuf, rwLen); break;
    case S_VERIFY: signal BlockRead.verifyDone[client](result); break;
    case S_CRC: signal BlockRead.computeCrcDone[client](result, crc, rwAddr, rwLen); break;
    }
  }

  task void signalDoneTask() {
    signalDone(STORAGE_OK);
  }

  block_addr_t calcNumBytes(block_addr_t addr) {

    block_addr_t pageOffset = addr % STORAGE_BLOCK_SIZE;
    block_addr_t numBytes = STORAGE_BLOCK_SIZE - pageOffset;
    block_addr_t bytesRemaining = rwAddr + rwLen - addr;

    if ( bytesRemaining < numBytes )
      numBytes = bytesRemaining;

    return numBytes;

  }

  command result_t BlockRead.read[blockstorage_t blockId](block_addr_t addr, uint8_t* buf, block_addr_t len) {

    block_addr_t lastBytes;

    if (admitRequest(blockId) == FAIL)
      return FAIL;

    curAddr = rwAddr = addr;
    rwBuf = buf;
    rwLen = len;

    for ( curAddr = addr; curAddr < addr + len; curAddr += lastBytes, buf += lastBytes ) {
      lastBytes = calcNumBytes(curAddr);
      if (call SectorStorage.read[blockId](curAddr, buf, lastBytes) == FAIL)
	return FAIL;
    }

    if (post signalDoneTask() == SUCCESS) {
      state = S_READ;
      return SUCCESS;
    }

    return FAIL;

  }

  command result_t BlockRead.verify[blockstorage_t blockId]() {
    if (admitRequest(blockId) == FAIL)
      return FAIL;
    return FAIL;
  }

  command result_t BlockRead.computeCrc[blockstorage_t blockId](block_addr_t addr, block_addr_t len) {

    block_addr_t lastBytes;

    if (admitRequest(blockId) == FAIL)
      return FAIL;

    curAddr = rwAddr = addr;
    rwLen = len;
    
    for ( curAddr = addr, crc = 0; curAddr < addr + len; curAddr += lastBytes ) {
      lastBytes = calcNumBytes(curAddr);
      if (call SectorStorage.computeCrc[blockId](&crc, crc, curAddr, lastBytes) == FAIL)
	return FAIL;
    }

    if (post signalDoneTask() == SUCCESS) {
      state = S_CRC;
      return SUCCESS;
    }

    return FAIL;

  }

  command result_t BlockWrite.erase[blockstorage_t blockId]() {

    if (admitRequest(blockId) == FAIL)
      return FAIL;

    state = S_ERASE;

    rwAddr = call StorageManager.getVolumeSize[blockId]() - STORAGE_BLOCK_SIZE;

    return check(call StorageManager.initSwap[blockId]());

  }

  event void StorageManager.initSwapDone[blockstorage_t blockId](storage_result_t result) {

    if (result != STORAGE_OK) {
      signalDone(result);
      return;
    }
    
    if (call StorageManager.commitSwap[blockId](rwAddr) == FAIL)
      signalDone(STORAGE_FAIL);

  }

  event void StorageManager.commitSwapDone[blockstorage_t blockId](storage_result_t result) {

    if (result != STORAGE_OK) {
      signalDone(result);
      return;
    }
    
    if ( rwAddr > 0 ) {
      rwAddr -= STORAGE_BLOCK_SIZE;
      if (call StorageManager.initSwap[blockId]() == FAIL)
	signalDone(STORAGE_FAIL);
      return;
    }
    
    signalDone(result);
    
  }
  
  command result_t BlockWrite.write[blockstorage_t blockId](block_addr_t addr, uint8_t* buf, block_addr_t len) {

    if (admitRequest(blockId) == FAIL)
      return FAIL;

    curAddr = rwAddr = addr;
    rwBuf = buf;
    rwLen = len;

    state = S_WRITE;

    return check(call SectorStorage.write[blockId](rwAddr, rwBuf, calcNumBytes(rwAddr)));

  }
  
  command result_t BlockWrite.commit[blockstorage_t blockId]() {
    
    if (admitRequest(blockId) == FAIL)
      return FAIL;
    
    return FAIL;
    
  }
  
  event void SectorStorage.writeDone[blockstorage_t blockId](storage_result_t result) {

    block_addr_t lastBytes = calcNumBytes(curAddr);
    uint8_t* tmpBuf;

    curAddr += lastBytes;

    if ( result != STORAGE_OK
	 || curAddr >= rwAddr + rwLen ) {
      signalDone(result);
      return;
    }

    tmpBuf = rwBuf + curAddr - rwAddr;

    if (call SectorStorage.write[blockId](curAddr, tmpBuf, calcNumBytes(curAddr)) == FAIL)
      signalDone(STORAGE_FAIL);

  }

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

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

}

--- NEW FILE: BlockWrite.nc ---
// $Id: BlockWrite.nc,v 1.1 2005/03/11 21:43:59 jwhui 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>
 */

includes BlockStorage;

interface BlockWrite {

  command result_t write(block_addr_t addr, uint8_t* buf, block_addr_t len);
  event void writeDone(storage_result_t result, block_addr_t addr, uint8_t* buf, block_addr_t len);

  command result_t erase();
  event void eraseDone(storage_result_t result);

  command result_t commit();
  event void commitDone(storage_result_t result);

}

--- NEW FILE: FlashWP.nc ---
// $Id: FlashWP.nc,v 1.1 2005/03/11 21:43:59 jwhui Exp $

/*									tab:2
 * "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>
 */

interface FlashWP {
  command result_t setWP();
  event result_t setWPDone(result_t result);
  command result_t clrWP();
  event result_t clrWPDone(result_t result);
}

--- NEW FILE: FlashWPC.nc ---
// $Id: FlashWPC.nc,v 1.1 2005/03/11 21:44:10 jwhui Exp $

/*									tab:2
 * "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>
 */

configuration FlashWPC {
  provides {
    interface FlashWP;
    interface StdControl;
  }
}

implementation {

  components FlashWPM, HALSTM25PC;

  StdControl = FlashWPM;
  FlashWP = FlashWPM;

  FlashWPM.HALSTM25P -> HALSTM25PC.HALSTM25P[0];

}

--- NEW FILE: FlashWPM.nc ---
// $Id: FlashWPM.nc,v 1.1 2005/03/11 21:44:10 jwhui Exp $

/*									tab:2
 * "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>
 */

module FlashWPM {
  provides {
    interface FlashWP;
    interface StdControl;
  }
  uses {
    interface HALSTM25P;
  }
}

implementation {

  uint8_t state;

  enum {
    S_IDLE,
    S_CLR,
    S_SET,
  };

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

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

  command result_t FlashWP.clrWP() {
    state = S_CLR;
    if (call HALSTM25P.writeSR(0x0) == FAIL) {
      state = S_IDLE;
      return FAIL;
    }
    return SUCCESS;
  }

  command result_t FlashWP.setWP() {
    state = S_SET;
    if (call HALSTM25P.writeSR(0x84) == FAIL) {
      state = S_IDLE;
      return FAIL;
    }
    return SUCCESS;
  }

  event void HALSTM25P.writeSRDone(result_t result) {
    uint8_t tmpState = state;
    state = S_IDLE;
    switch(tmpState) {
    case S_CLR: signal FlashWP.clrWPDone(result); break;
    case S_SET: signal FlashWP.setWPDone(result); break;
    }
  }

  event void HALSTM25P.pageProgramDone(result_t result) { ; }
  event void HALSTM25P.sectorEraseDone(result_t result) { ; }
  event void HALSTM25P.bulkEraseDone(result_t result) { ; }
  event void HALSTM25P.readSRDone(result_t result, uint8_t val) { ; }

}

--- NEW FILE: FormatStorage.nc ---
// $Id: FormatStorage.nc,v 1.1 2005/03/11 21:44:10 jwhui Exp $

/*									tab:2
 * "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>
 */

includes Storage;

interface FormatStorage {

  command result_t init();

  command result_t allocate(volume_id_t id, storage_addr_t size);
  command result_t allocateFixed(volume_id_t id, storage_addr_t addr, storage_addr_t size);

  command result_t commit();
  event void commitDone(storage_result_t result);

}

--- NEW FILE: FormatStorageC.nc ---
// $Id: FormatStorageC.nc,v 1.1 2005/03/11 21:44:10 jwhui Exp $

/*									tab:2
 * "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>
 */

includes crc;

configuration FormatStorageC {
  provides {
    interface FormatStorage;
  }
}

implementation {

  components FormatStorageM, HALSTM25PC, Main;

  FormatStorage = FormatStorageM;

  Main.StdControl -> FormatStorageM;
  Main.StdControl -> HALSTM25PC;

  FormatStorageM.HALSTM25P -> HALSTM25PC.HALSTM25P[unique("HALSTM25P")];

}

--- NEW FILE: FormatStorageM.nc ---
// $Id: FormatStorageM.nc,v 1.1 2005/03/11 21:44:10 jwhui Exp $

/*									tab:2
 * "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>
 */

module FormatStorageM {
  provides {
    interface FormatStorage;
    interface StdControl;
  }
  uses {
    interface HALSTM25P;
  }
}

implementation {

  SectorTable sectorTable;
  volume_id_t curVolume;

  uint8_t state;

  enum {
    S_INIT,
    S_COMMIT,
    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() {

    volume_id_t i;

    if (state == S_COMMIT)
      return FAIL;

    state = S_INIT;

    for ( i = 0; i < STM25P_NUM_SECTORS; i++ )
      sectorTable.sector[i].volumeId = STM25P_INVALID_VOLUME_ID;
    sectorTable.version = 0;

    return SUCCESS;

  }

  command result_t FormatStorage.allocate(volume_id_t id, storage_addr_t size) {

    volume_id_t freeSectors;
    uint8_t curSector;
    volume_id_t i;

    if (state != S_INIT)
      return FAIL;

    // size must be a multiple of sector size
    if (size % STORAGE_BLOCK_SIZE)
      return FAIL;

    size /= STORAGE_BLOCK_SIZE;

    for ( i = 0, freeSectors = 0; i < STM25P_NUM_SECTORS; i++ ) {
      // check if id is already taken
      if (sectorTable.sector[i].volumeId == id)
	return FAIL;
      // count number of free sectors
      if (sectorTable.sector[i].volumeId == STM25P_INVALID_VOLUME_ID)
	freeSectors++;
    }

    // check if there are enough free sectors
    if (freeSectors < size)
      return FAIL;

    for ( i = 0, curSector = 0; i < STM25P_NUM_SECTORS; i++ ) {
      if (sectorTable.sector[i].volumeId == STM25P_INVALID_VOLUME_ID) {
	sectorTable.sector[i].volumeId = id;
	sectorTable.sector[i].sectorId = curSector++;
	sectorTable.sector[i].isFixed = FALSE;
	if (--size == 0)
	  return SUCCESS;
      }
    }

    // something bad happened
    return FAIL;

  }

  /**
   * Not implemented
   */
  command result_t FormatStorage.allocateFixed(volume_id_t id, storage_addr_t addr, storage_addr_t size) {

    volume_id_t freeSectors;
    uint8_t curSector;
    volume_id_t i;

    if (state != S_INIT)
      return FAIL;

    // addr must be a multiple of sector size
    if (addr % STM25P_SECTOR_SIZE)
      return FAIL;

    // size must be a multiple of storage block size
    if (size % STORAGE_BLOCK_SIZE)
      return FAIL;

    addr /= STM25P_SECTOR_SIZE;
    size /= STORAGE_BLOCK_SIZE;

    for ( i = addr, freeSectors = 0; i < STM25P_NUM_SECTORS; i++ ) {
      // check if sector is already taken
      if (sectorTable.sector[i].volumeId != STM25P_INVALID_VOLUME_ID)
	return FAIL;
      // count number of free sectors
      else
	freeSectors++;
    }    
    
    // check if there are enough free sectors
    if (freeSectors < size)
      return FAIL;
    
    for ( i = addr, curSector = 0; i < STM25P_NUM_SECTORS; i++ ) {
      if (sectorTable.sector[i].volumeId == STM25P_INVALID_VOLUME_ID) {
	sectorTable.sector[i].volumeId = id;
	sectorTable.sector[i].sectorId = curSector++;
	sectorTable.sector[i].isFixed = TRUE;
	if (--size == 0)
	  return SUCCESS;
      }
    }
    
    return FAIL;

  }
   
  uint16_t computeSectorTableCrc() {
    
    uint8_t* buf = (uint8_t*)&sectorTable;
    uint16_t crc;
    uint8_t i;
    
    for ( i = 0, crc = 0; i < sizeof(SectorTable) - 2; i++, buf++ )
      crc = crcByte(crc, *buf);
    
    return crc;

  }

  command result_t FormatStorage.commit() {

    if (state != S_INIT)
      return FAIL;

    state = S_COMMIT;
    curVolume = 0;

    sectorTable.crc = computeSectorTableCrc();

    if (call HALSTM25P.sectorErase(STM25P_SECTOR_SIZE*curVolume) == FAIL) {
      state = S_INIT;
      return FAIL;
    }

    return SUCCESS;

  }

  void writeVolumeMetadata() {

    stm25p_addr_t addr;
    
    addr = STM25P_SECTOR_SIZE*curVolume + STORAGE_BLOCK_SIZE;
    
    if (call HALSTM25P.pageProgram(addr, (uint8_t*)&sectorTable, 
				   sizeof(sectorTable)) == FAIL) {
      signalDone(STORAGE_FAIL);
      return;
    }

  }

  event void HALSTM25P.sectorEraseDone(result_t result) { 

    if (result != STORAGE_OK) {
      signalDone(result);
      return;
    }

    curVolume++;
    if ( curVolume < STM25P_NUM_SECTORS ) {
      if (call HALSTM25P.sectorErase(STM25P_SECTOR_SIZE*curVolume) == FAIL)
	signalDone(STORAGE_FAIL);
      return;
    }
    
    curVolume = 0;
    writeVolumeMetadata();

  }

  event void HALSTM25P.pageProgramDone(result_t result) {

    if (result != STORAGE_OK) {
      signalDone(result);
      return;
    }
    
    curVolume++;
    if ( curVolume < STM25P_NUM_SECTORS ) {
      writeVolumeMetadata();
      return;
    }

    signalDone(STORAGE_OK);

  }

  event void HALSTM25P.bulkEraseDone(result_t result) { ; }
  event void HALSTM25P.readSRDone(result_t result, uint8_t val) { ; }
  event void HALSTM25P.writeSRDone(result_t result) { ; }

}

--- NEW FILE: HALSTM25P.h ---
// $Id: HALSTM25P.h,v 1.1 2005/03/11 21:44:10 jwhui 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>
 */

#ifndef __STM25P_H__
#define __STM25P_H__

#include "Storage.h"

enum {
  STM25P_PAGE_SIZE = 256,
  STM25P_SECTOR_SIZE_LOG2 = 16,
  STM25P_SECTOR_SIZE = (uint32_t)1<<STM25P_SECTOR_SIZE_LOG2,
  STM25P_NUM_SECTORS = 16,
};

enum {
  STM25P_INVALID_SIG = 0xff,
  STM25P_INVALID_VOLUME_ID = 0xff,
};

enum {
  STM25P_ADDR_SIZE       = 3,
  STM25P_FR_DUMMY_BYTES  = 1,
  STM25P_RES_DUMMY_BYTES = 3,
};

enum {
                           // I, A, D, T, R
  STM25P_WREN      = 0x06, // 1, 0, 0, 0, 0
  STM25P_WRDI      = 0x04, // 1, 0, 0, 0, 0
  STM25P_RDSR      = 0x05, // 1, 0, 0, 0, 1
  STM25P_WRSR      = 0x01, // 1, 0, 0, 1, 0
  STM25P_READ      = 0x03, // 1, 3, 0, 0, N
  STM25P_FAST_READ = 0x0b, // 1, 3, 1, 0, N
  STM25P_PP        = 0x02, // 1, 3, 0, N, 0
  STM25P_SE        = 0xd8, // 1, 3, 0, 0, 0
  STM25P_BE        = 0xc7, // 1, 0, 0, 0, 0
  STM25P_DP        = 0xb9, // 1, 0, 0, 0, 0
  STM25P_RES       = 0xab, // 1, 0, 3, 0, 1
  STM25P_CRC       = 0xff, // not really an instruction
};

typedef uint8_t  stm25p_status_t;
typedef uint32_t stm25p_addr_t;
typedef uint8_t  stm25p_sig_t;

typedef struct {
  volume_id_t volumeId;
  uint8_t sectorId : 7;
  bool isFixed : 1;
} SectorMetadata;

typedef struct {
  SectorMetadata sector[STM25P_NUM_SECTORS];
  int16_t  version;
  uint16_t crc;
} SectorTable;

enum {
  STM25P_INVALID_VERSION = 0xffff,
};

enum {
  STM25P_INVALID_ADDR = 0xffffffff,
};

enum {
  STORAGE_BLOCK_SIZE = STM25P_SECTOR_SIZE - sizeof(SectorTable),
};

typedef stm25p_addr_t storage_addr_t;

#endif

--- NEW FILE: HALSTM25P.nc ---
// $Id: HALSTM25P.nc,v 1.1 2005/03/11 21:44:10 jwhui 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>
 */

includes HALSTM25P;

interface HALSTM25P {

  command result_t read(stm25p_addr_t addr, uint8_t* data, stm25p_addr_t len);

  command result_t pageProgram(stm25p_addr_t addr, uint8_t* data, stm25p_addr_t len);
  event void pageProgramDone(result_t result);

  command result_t sectorErase(stm25p_addr_t addr);
  event void sectorEraseDone(result_t result);

  command result_t bulkErase();
  event void bulkEraseDone(result_t result);

  command result_t readSR();
  event void readSRDone(result_t result, uint8_t value);

  command result_t writeSR(uint8_t value);
  event void writeSRDone(result_t result);

  command result_t computeCrc(uint16_t* crcResult, uint16_t crc, stm25p_addr_t addr, stm25p_addr_t len);

  command stm25p_sig_t getSignature();

}

--- NEW FILE: HALSTM25PC.nc ---
// $Id: HALSTM25PC.nc,v 1.1 2005/03/11 21:44:10 jwhui 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>
 */

includes crc;
includes HALSTM25P;

configuration HALSTM25PC {
  provides {
    interface StdControl;
    interface HALSTM25P[volume_t volume];
  }
}

implementation {
  components HALSTM25PM, HPLSTM25PC, LedsC as Leds;

  StdControl = HALSTM25PM;
  StdControl = HPLSTM25PC;
  HALSTM25P = HALSTM25PM;

  HALSTM25PM.HPLSTM25P -> HPLSTM25PC;
  HALSTM25PM.Leds -> Leds;
}

--- NEW FILE: HALSTM25PM.nc ---
// $Id: HALSTM25PM.nc,v 1.1 2005/03/11 21:44:10 jwhui 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>
 */

module HALSTM25PM {
  provides {
    interface StdControl;
    interface HALSTM25P[volume_t volume];
  }
  uses {
    interface HPLSTM25P;
    interface Leds;
  }
}

implementation {
  
  enum {
    S_POWEROFF, // deep power-down state
    S_POWERON,  // awake state, no command in progress
  };

  stm25p_sig_t signature;
  uint16_t crcScratch;
  uint8_t curCmd;
  volume_t curVolume;

  storage_result_t signalResult;
  uint8_t returnVal;

  void sendCmd(uint8_t cmd, stm25p_addr_t addr, uint8_t* data, stm25p_addr_t len);

  command result_t StdControl.init() {
    curCmd = S_POWEROFF;
    signature = STM25P_INVALID_SIG;
    return SUCCESS;
  }

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

  void actualSignalDone() {
    uint8_t tmpCmd = curCmd;
    curCmd = S_POWERON;

    switch(tmpCmd) {
    case STM25P_PP: signal HALSTM25P.pageProgramDone[curVolume](signalResult); break;
    case STM25P_SE: signal HALSTM25P.sectorEraseDone[curVolume](signalResult); break;
    case STM25P_BE: signal HALSTM25P.bulkEraseDone[curVolume](signalResult); break;
    case STM25P_RDSR: signal HALSTM25P.readSRDone[curVolume](signalResult, returnVal); break;
    case STM25P_WRSR: signal HALSTM25P.writeSRDone[curVolume](signalResult); break;
    }
  }

  void checkPost(bool result) {
    if (result == FAIL) {
      signalResult = STORAGE_FAIL;
      actualSignalDone();
    }
  }

  task void signalDone() {
    actualSignalDone();
  }

  bool isWriting() {
    uint8_t status;
    if (call HPLSTM25P.getBus() == FAIL)
      return TRUE;
    sendCmd(STM25P_RDSR, 0, &status, sizeof(status));
    call HPLSTM25P.releaseBus();
    return (status & 0x1) ? TRUE : FALSE;
  }

  // probably better to use a timer since write operations can take on
  // the order of seconds to complete
  task void checkWriteDone() {
    if (isWriting()) {
      checkPost(post checkWriteDone());
      return;
    }
    signalResult = STORAGE_OK;
    checkPost(post signalDone());
  }

  void sendCmd(uint8_t cmd, stm25p_addr_t addr, uint8_t* data, stm25p_addr_t len) {

    uint8_t addrBytes[STM25P_ADDR_SIZE];
    stm25p_addr_t i;

    // start command
    switch(cmd) {
    case STM25P_CRC: call HPLSTM25P.beginCmd(STM25P_READ); break;
    default: call HPLSTM25P.beginCmd(cmd); break;
    }

    // address
    switch(cmd) {
    case STM25P_READ: case STM25P_FAST_READ: case STM25P_PP: 
    case STM25P_SE: case STM25P_CRC:
      for ( i = 0; i < STM25P_ADDR_SIZE; i++ )
	addrBytes[i] = (addr >> ((STM25P_ADDR_SIZE-1-i)*8)) & 0xff;
      call HPLSTM25P.txBuf(addrBytes, STM25P_ADDR_SIZE);
      break;
    }

    // dummy bytes
    switch(cmd) {
    case STM25P_FAST_READ:
      call HPLSTM25P.txBuf(addrBytes, STM25P_FR_DUMMY_BYTES);
      break;
    case STM25P_RES:
      call HPLSTM25P.txBuf(addrBytes, STM25P_RES_DUMMY_BYTES);
      break;
    }

    // data
    switch(cmd) {
    case STM25P_RDSR: case STM25P_READ: case STM25P_FAST_READ: case STM25P_RES:
      call HPLSTM25P.rxBuf(data, len);
      break;
    case STM25P_WRSR: case STM25P_PP:
      call HPLSTM25P.txBuf(data, len);
      break;
    case STM25P_CRC:
      call HPLSTM25P.computeCrc(&crcScratch, len);
      break;
    }

    // end command
    call HPLSTM25P.endCmd();

  }

  void powerOff() {
    sendCmd(STM25P_DP, 0, NULL, 0);
    curCmd = S_POWEROFF;
  }

  void powerOn() {
    sendCmd(STM25P_RES, 0, &signature, sizeof(signature));
    TOSH_uwait(2); // wait at least 1.8us to power on
    curCmd = S_POWERON;
  }

  result_t newRequest(uint8_t cmd, volume_t volume, stm25p_addr_t addr, uint8_t* data, stm25p_addr_t len) {

    // make sure flash is powered on
    if (curCmd == S_POWEROFF)
      powerOn();
    // make sure nothing else is in progress
    else if (curCmd != S_POWERON)
      return FAIL;
    // make sure we can get the bus
    else if (call HPLSTM25P.getBus() == FAIL)
      return FAIL;

    curVolume = volume;
    
    curCmd = cmd;
    
    // enable writes if needed
    if (curCmd == STM25P_WRSR || curCmd == STM25P_PP || curCmd == STM25P_SE || curCmd == STM25P_BE)
      sendCmd(STM25P_WREN, 0, NULL, 0);
    
    // send command
    sendCmd(curCmd, addr, data, len);

    call HPLSTM25P.releaseBus();

    // setup check for write done
    if (curCmd == STM25P_WRSR || curCmd == STM25P_PP || curCmd == STM25P_SE || curCmd == STM25P_BE)
      checkPost(post checkWriteDone());
    else
      curCmd = S_POWERON;

    return SUCCESS;

  }

  command result_t HALSTM25P.read[volume_t volume](stm25p_addr_t addr, uint8_t* data, stm25p_addr_t len) {
    return newRequest(STM25P_READ, volume, addr, data, len);
  }

  command result_t HALSTM25P.pageProgram[volume_t volume](stm25p_addr_t addr, uint8_t* data, stm25p_addr_t len) {
    return newRequest(STM25P_PP, volume, addr, data, len);
  }

  command result_t HALSTM25P.sectorErase[volume_t volume](stm25p_addr_t addr) {
    return newRequest(STM25P_SE, volume, addr, NULL, 0);
  }

  command result_t HALSTM25P.bulkErase[volume_t volume]() {
    return newRequest(STM25P_BE, volume, 0, NULL, 0);
  }

  command result_t HALSTM25P.readSR[volume_t volume]() {
    return newRequest(STM25P_RDSR, volume, 0, &returnVal, 1);
  }

  command result_t HALSTM25P.writeSR[volume_t volume](uint8_t value) {
    return newRequest(STM25P_WRSR, volume, 0, &value, 1);
  }

  command result_t HALSTM25P.computeCrc[volume_t volume](uint16_t* crcResult, uint16_t crc, stm25p_addr_t addr, stm25p_addr_t len) {
    crcScratch = crc;
    if (newRequest(STM25P_CRC, volume, addr, NULL, len) == FAIL)
      return FAIL;
    *crcResult = crcScratch;
    return SUCCESS;
  }

  command stm25p_sig_t HALSTM25P.getSignature[volume_t volume]() { 
    return signature; 
  }
  
  default event void HALSTM25P.pageProgramDone[volume_t volume](result_t result) { ; }
  default event void HALSTM25P.sectorEraseDone[volume_t volume](result_t result) { ; }
  default event void HALSTM25P.bulkEraseDone[volume_t volume](result_t result) { ; }
  default event void HALSTM25P.readSRDone[volume_t volume](result_t result, uint8_t val) { ; }
  default event void HALSTM25P.writeSRDone[volume_t volume](result_t result) { ; }

}

--- NEW FILE: HPLSTM25P.nc ---
// $Id: HPLSTM25P.nc,v 1.1 2005/03/11 21:44:10 jwhui 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>
 */

interface HPLSTM25P {
  async command result_t getBus();
  async command result_t releaseBus();
  async command result_t beginCmd(uint8_t cmd);
  async command result_t endCmd();
  async command result_t hold();
  async command result_t unhold();
  async command result_t txBuf(uint8_t* buf, stm25p_addr_t len);
  async command result_t rxBuf(uint8_t* buf, stm25p_addr_t len);
  async command result_t computeCrc(uint16_t* crcResult, stm25p_addr_t len);
}

--- NEW FILE: LogRead.nc ---
// $Id: LogRead.nc,v 1.1 2005/03/11 21:44:10 jwhui Exp $

/*									tab:2
 * "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>
 */

includes LogStorage;

interface LogRead {
  
  command result_t read(uint8_t* data, log_len_t numBytes);
  event void readDone(storage_result_t result, uint8_t* data, log_len_t numBytes);
  
  command result_t seek(log_cookie_t cookie);
  event void seekDone(storage_result_t result, log_cookie_t cookie);
  
}

--- NEW FILE: LogStorage.h ---
// $Id: LogStorage.h,v 1.1 2005/03/11 21:44:11 jwhui Exp $

/*									tab:2
 * "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>
 */

#ifndef __LOG_STORAGE_H__
#define __LOG_STORAGE_H__

typedef uint32_t log_len_t;
typedef uint32_t log_cookie_t;
typedef uint8_t logstorage_t;

typedef uint16_t log_block_addr_t;

typedef struct {
  log_cookie_t cookie;
} LogSectorHeader;

typedef struct {
  log_block_addr_t length : 12;
  log_block_addr_t flags  : 4;
} LogBlockHeader;

enum {
  LOG_BLOCK_ALLOCATED = 1 << 0,
  LOG_BLOCK_VALID = 1 << 1,
};

enum {
  LOG_BLOCK_MAX_LENGTH = 1 << 8,
  LOG_BLOCK_LENGTH_MASK = (1 << 12) - 1,
  LOG_MAX_COOKIE = 0xffffffff,
};

#endif

--- NEW FILE: LogStorageC.nc ---
// $Id: LogStorageC.nc,v 1.1 2005/03/11 21:44:11 jwhui Exp $

/*									tab:2
 * "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>
 */

includes LogStorage;

configuration LogStorageC {
  provides {
    interface Mount[logstorage_t logId];
    interface LogRead[logstorage_t logId];
    interface LogWrite[logstorage_t logId];
    interface StorageRemap[logstorage_t logId];
  }
}

implementation {

  components LogStorageM, Main, StorageManagerC, LedsC as Leds;

  Mount = LogStorageM.Mount;
  LogRead = LogStorageM.LogRead;
  LogWrite = LogStorageM.LogWrite;
  StorageRemap = StorageManagerC.StorageRemap;

  Main.StdControl -> StorageManagerC;

  LogStorageM.SectorStorage -> StorageManagerC.SectorStorage;
  LogStorageM.StorageManager -> StorageManagerC;
  LogStorageM.ActualMount -> StorageManagerC.Mount;
  LogStorageM.Leds -> Leds;
  
}

--- NEW FILE: LogStorageM.nc ---
// $Id: LogStorageM.nc,v 1.1 2005/03/11 21:44:11 jwhui Exp $

/*									tab:2
 * "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>
 */

module LogStorageM {
  provides {
    interface Mount[logstorage_t logId];
    interface LogRead[logstorage_t logId];
    interface LogWrite[logstorage_t logId];
  }
  uses {
    interface SectorStorage[logstorage_t logId];
    interface Leds;
    interface Mount as ActualMount[logstorage_t logId];
    interface StorageManager[logstorage_t logId];
  }
}

implementation {

  enum {
    S_IDLE,
    S_MOUNT,
    S_ERASE,
    S_WRITE_SECTOR_HEADER,
    S_INIT_BLOCK_HEADER,
    S_COMMIT_BLOCK_HEADER,
    S_APPEND,
    S_SYNC,
    S_READ,
    S_SEEK,
  };
  
  LogSectorHeader sectorHeader;
  LogBlockHeader blockHeader;
  
  log_len_t rwLen, curLen, lastLen;
  uint8_t* rwData;
  
  uint8_t state;
  logstorage_t client;
  volume_id_t volumeId;

  log_cookie_t curReadCookie, curWriteCookie;
  log_block_addr_t curWriteBlockPos, curReadBlockLen;

  void signalDone(storage_result_t result) {

    uint8_t tmpState = state;

    state = S_IDLE;

    switch(tmpState) {
    case S_MOUNT: signal Mount.mountDone[client](result, volumeId); break;
    case S_ERASE: signal LogWrite.eraseDone[client](result); break;
    case S_APPEND: signal LogWrite.appendDone[client](result, rwData, rwLen); break;
    case S_SYNC: signal LogWrite.syncDone[client](result); break;
    case S_READ: signal LogRead.readDone[client](result, rwData, rwLen); break;
    case S_SEEK: signal LogRead.seekDone[client](result, curReadCookie); break;
    }

  }

  task void signalDoneTask() {
    signalDone(STORAGE_OK);
  }

  bool admitRequest(logstorage_t logId) {
    if (state != S_IDLE)
      return FALSE;
    client = logId;
    return TRUE;
  }

  command result_t Mount.mount[logstorage_t logId](volume_id_t id) {
    if (admitRequest(logId) == FAIL)
      return FAIL;
    state = S_MOUNT;
    return call ActualMount.mount[logId](id);
  }

  event void ActualMount.mountDone[logstorage_t logId](storage_result_t result, volume_id_t id) {

    stm25p_addr_t volumeSize = call StorageManager.getVolumeSize[client]();
    uint8_t numSectors = volumeSize / STORAGE_BLOCK_SIZE;
    uint8_t i;

    volumeId = id;

    curWriteCookie = curReadCookie = 0;
    curWriteBlockPos = curReadBlockLen = 0;

    // find sector with smallest/largest sector header cookie
    for ( i = 0, curReadCookie = LOG_MAX_COOKIE, curWriteCookie = 0; i < numSectors; i++ ) {
      if (call SectorStorage.read[client](i*STORAGE_BLOCK_SIZE, (uint8_t*)&sectorHeader, 
					  sizeof(sectorHeader)) == FAIL) {
	signalDone(STORAGE_FAIL);
	return;
      }
      if (!~sectorHeader.cookie)
	continue;
      if (sectorHeader.cookie < curReadCookie)
	curReadCookie = sectorHeader.cookie;
      if (sectorHeader.cookie > curWriteCookie)
	curWriteCookie = sectorHeader.cookie;
    }

    call Leds.yellowOn();

    curWriteCookie += sizeof(LogSectorHeader);
    
    // advance curWriteCookie to last log block
    blockHeader.length = 0;
    do {
      curWriteCookie += blockHeader.length;
      if (call SectorStorage.read[client](curWriteCookie, (uint8_t*)&blockHeader, 
					  sizeof(blockHeader)) == FAIL) {
	signalDone(STORAGE_FAIL);
	return;
      }
    } while ( ((~blockHeader.flags) & LOG_BLOCK_ALLOCATED) 
	      && (~blockHeader.length)
	      && curWriteCookie < volumeSize );

    call Leds.greenOn();
    
    signalDone(STORAGE_OK);

  }

  command result_t LogRead.read[logstorage_t logId](uint8_t* data, log_len_t numBytes) {

    log_len_t lastBytes;

    if ( admitRequest(logId) == FAIL
	 || curReadCookie >= curWriteCookie )
      return FAIL;
    
    while ( numBytes > 0 ) {

      // read sector header
      if ( !(curReadCookie % STORAGE_BLOCK_SIZE) )
	curReadCookie += sizeof(LogSectorHeader);
	
      // read block header
      if ( curReadBlockLen == 0 ) {
	blockHeader.length = 0;
	do {
	  curReadCookie += blockHeader.length;
	  if (call SectorStorage.read[logId](curReadCookie, (uint8_t*)&blockHeader, 
					     sizeof(blockHeader)) == FAIL)
	    return FAIL;
	} while ( (~blockHeader.flags) & LOG_BLOCK_ALLOCATED
		  && curReadCookie + blockHeader.length < curWriteCookie
		  && !( (~blockHeader.flags) & LOG_BLOCK_VALID ) );
	curReadBlockLen = blockHeader.length - sizeof(LogBlockHeader);
	curReadCookie += sizeof(LogBlockHeader);
      }

      // check for end of log block
      lastBytes = numBytes;
      if ( curReadBlockLen < lastBytes )
	lastBytes = curReadBlockLen;

      if (call SectorStorage.read[logId](curReadCookie, data, lastBytes) == FAIL)
	return FAIL;

      curReadCookie += lastBytes;
      data += lastBytes;
      curReadBlockLen -= lastBytes;
      numBytes -= lastBytes;

    }

    if (post signalDoneTask() == SUCCESS) {
      state = S_READ;
      return SUCCESS;
    }

    return FAIL;

  }

  command result_t LogRead.seek[logstorage_t logId](log_cookie_t cookie) {

    if (admitRequest(logId) == FAIL)
      return FAIL;
    
    return FAIL;
    
  }

  command result_t LogWrite.erase[logstorage_t logId]() {

    if (admitRequest(logId) == FAIL)
      return FAIL;

    state = S_ERASE;

    curWriteCookie = call StorageManager.getVolumeSize[logId]() - STORAGE_BLOCK_SIZE;

    if (call StorageManager.initSwap[logId]() == FAIL) {
      state = S_IDLE;
      return FAIL;
    }

    return SUCCESS;

  }

  bool newEntryFits() {

    log_len_t remainingBytes = rwLen;
    log_len_t totalBytes;
    log_len_t tmp;

    // fill current log block
    totalBytes = LOG_BLOCK_MAX_LENGTH - curWriteBlockPos;
    remainingBytes -= totalBytes;
    
    // fill x log blocks
    tmp = (remainingBytes / LOG_BLOCK_MAX_LENGTH)*(sizeof(LogBlockHeader) + LOG_BLOCK_MAX_LENGTH);
    totalBytes += tmp;
    remainingBytes -= tmp;
    
    // complete final log block
    if (remainingBytes)
      totalBytes += remainingBytes + sizeof(LogBlockHeader);

    tmp = call StorageManager.getVolumeSize[client]() - curWriteCookie;

    // compensate for log sector header
    tmp -= (tmp / STORAGE_BLOCK_SIZE) * sizeof(LogSectorHeader);

    return (totalBytes < tmp);
    
  }
  
  result_t appendData() {
    
    log_len_t tmp;

    if ( (curLen == 0) && !newEntryFits() )
      return FAIL;

    // commit log block header if at: (1) max block len or (2) end of sector
    if ( curWriteBlockPos >= LOG_BLOCK_MAX_LENGTH
	 || ( curWriteBlockPos && !(curWriteCookie % STORAGE_BLOCK_SIZE) ) ) {
      call Leds.yellowToggle();
      blockHeader.length = curWriteBlockPos;
      blockHeader.flags = ~(LOG_BLOCK_VALID + LOG_BLOCK_ALLOCATED);
      lastLen = sizeof(blockHeader);
      state = S_COMMIT_BLOCK_HEADER;
      return call SectorStorage.write[client](curWriteCookie-curWriteBlockPos, 
					      (uint8_t*)&blockHeader, lastLen);
    }

    // write cookie if at start of sector
    if ( !(curWriteCookie % STORAGE_BLOCK_SIZE) ) {
      sectorHeader.cookie = curWriteCookie;
      lastLen = sizeof(sectorHeader);
      state = S_WRITE_SECTOR_HEADER;
      return call SectorStorage.write[client](curWriteCookie, (uint8_t*)&sectorHeader, lastLen);
    }

    // begin log block header
    if ( !curWriteBlockPos ) {
      blockHeader.length = LOG_BLOCK_LENGTH_MASK;
      blockHeader.flags = ~(LOG_BLOCK_ALLOCATED);
      lastLen = sizeof(blockHeader);
      state = S_INIT_BLOCK_HEADER;
      return call SectorStorage.write[client](curWriteCookie, (uint8_t*)&blockHeader, lastLen);
    }

    // write data

    // check for sector boundary
    lastLen = rwLen;
    tmp = STORAGE_BLOCK_SIZE - (curWriteCookie % STORAGE_BLOCK_SIZE);
    if ( tmp < lastLen )
      lastLen = tmp;
    
    // check for log block boundary
    tmp = LOG_BLOCK_MAX_LENGTH - curWriteBlockPos;
    if ( tmp < lastLen )
      lastLen = tmp;
    
    state = S_APPEND;
    return call SectorStorage.write[client](curWriteCookie, rwData + curLen, lastLen);

  }

  command result_t LogWrite.append[logstorage_t logId](uint8_t* data, log_len_t numBytes) {

    if (admitRequest(logId) == FAIL)
      return FAIL;

    rwData = data;
    rwLen = numBytes;
    curLen = 0;

    state = S_APPEND;

    if (appendData() == FAIL) {
      state = S_IDLE;
      return FAIL;
    }

    return SUCCESS;

  }

  command result_t LogWrite.sync[logstorage_t logId]() {

    if (admitRequest(logId) == FAIL)
      return FAIL;

    return FAIL;

  }

  command log_cookie_t LogWrite.currentOffset[logstorage_t logId]() {
    return curWriteCookie;
  }

  event void StorageManager.initSwapDone[logstorage_t logId](storage_result_t result) {
    
    if (result != STORAGE_OK) {
      signalDone(result);
      return;
    }
    
    if (call StorageManager.commitSwap[logId](curWriteCookie) == FAIL)
      signalDone(STORAGE_FAIL);

  }

  event void StorageManager.commitSwapDone[logstorage_t logId](storage_result_t result) {
    
    if (result != STORAGE_OK) {
      signalDone(result);
      return;
    }
    
    // check for more sectors to erase
    if ( curWriteCookie > 0 ) {
      curWriteCookie -= STORAGE_BLOCK_SIZE;
      if (call StorageManager.initSwap[logId]() == FAIL)
	signalDone(STORAGE_FAIL);
      return;
    }

    curWriteBlockPos = 0;

    signalDone(STORAGE_OK);

  }

  event void SectorStorage.writeDone[logstorage_t logId](storage_result_t result) { 

    if (state != S_COMMIT_BLOCK_HEADER)
      curWriteCookie += lastLen;

    if (result != STORAGE_OK) {
      signalDone(result); 
      return;
    }

    switch(state) {
    case S_WRITE_SECTOR_HEADER: 
      break;
    case S_INIT_BLOCK_HEADER: 
      curWriteBlockPos += lastLen;
      break;
    case S_COMMIT_BLOCK_HEADER: 
      if (curReadCookie >= curWriteCookie-curWriteBlockPos)
	curReadBlockLen = curWriteCookie-curReadCookie;
      curWriteBlockPos = 0;
      break;
    case S_APPEND: 
      curWriteBlockPos += lastLen;
      curLen += lastLen;
      break;
    }

    if (curLen >= rwLen) {
      signalDone(result);
    }
    else if (appendData() == FAIL) {
      state = S_APPEND;
      signalDone(STORAGE_FAIL);
    }
    
  }

  default event void LogRead.readDone[logstorage_t logId](storage_result_t result, uint8_t* data, log_len_t numBytes) { ; }
  default event void LogRead.seekDone[logstorage_t logId](storage_result_t result, log_len_t cookie) { ; }
  default event void LogWrite.eraseDone[logstorage_t logId](storage_result_t result) { ; }
  default event void LogWrite.appendDone[logstorage_t logId](storage_result_t result, uint8_t* data, log_len_t numBytes) { ; }
  default event void LogWrite.syncDone[logstorage_t logId](storage_result_t result) { ; }

  default event void Mount.mountDone[logstorage_t logId](storage_result_t result, volume_id_t id) { ; }

}

--- NEW FILE: LogWrite.nc ---
// $Id: LogWrite.nc,v 1.1 2005/03/11 21:44:11 jwhui Exp $

/*									tab:2
 * "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>
 */

includes LogStorage;

interface LogWrite {

  command result_t erase();
  event void eraseDone(storage_result_t result);
  
  command result_t append(uint8_t* data, log_len_t numBytes);
  event void appendDone(storage_result_t result, uint8_t* data, log_len_t numBytes);
  
  command result_t sync();
  event void syncDone(storage_result_t result);

  command log_cookie_t currentOffset();
  
}

--- NEW FILE: Mount.nc ---
// $Id: Mount.nc,v 1.1 2005/03/11 21:44:11 jwhui Exp $

/*									tab:2
 * "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>
 */

includes Storage;

interface Mount {
  command result_t mount(volume_id_t id);
  event void mountDone(storage_result_t result, volume_id_t id);
}

--- NEW FILE: SectorStorage.nc ---
// $Id: SectorStorage.nc,v 1.1 2005/03/11 21:44:11 jwhui Exp $

/*									tab:2
 * "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>
 */

interface SectorStorage {

  command result_t read(stm25p_addr_t addr, uint8_t* data, stm25p_addr_t len);

  command result_t write(stm25p_addr_t addr, uint8_t* data, stm25p_addr_t len);
  event void writeDone(storage_result_t result);
  
  command result_t computeCrc(uint16_t* crcResult, uint16_t crc, stm25p_addr_t addr, stm25p_addr_t len);

}

--- NEW FILE: Storage.h ---
// $Id: Storage.h,v 1.1 2005/03/11 21:44:11 jwhui Exp $

/*									tab:2
 * "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>
 */

#ifndef __STORAGE_H__
#define __STORAGE_H__

enum {
  STORAGE_OK,
  STORAGE_FAIL,
};

enum {
  STORAGE_INVALID_ADDR = (uint32_t)0xffff,
};

typedef uint8_t volume_t;
typedef uint8_t volume_id_t;
typedef uint8_t storage_result_t;

#include "Storage_chip.h"

#endif

--- NEW FILE: StorageManager.nc ---
// $Id: StorageManager.nc,v 1.1 2005/03/11 21:44:11 jwhui Exp $

/*									tab:2
 * "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>
 */

interface StorageManager {

  command stm25p_addr_t getVolumeSize();

  command result_t initSwap();
  event void initSwapDone(storage_result_t result);

  command result_t commitSwap(stm25p_addr_t addr);
  event void commitSwapDone(storage_result_t result);

}

--- NEW FILE: StorageManagerC.nc ---
// $Id: StorageManagerC.nc,v 1.1 2005/03/11 21:44:11 jwhui 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>
 */

configuration StorageManagerC {
  provides {
    interface SectorStorage[volume_t volume];
    interface SectorStorage as Swap[volume_t volume];
    interface Mount[volume_t volume];
    interface StdControl;
    interface StorageRemap[volume_t volume];
    interface StorageManager[volume_t volume];
  }
}

implementation {

  components HALSTM25PC, StorageManagerM, LedsC;
  
  StdControl = StorageManagerM;
  StdControl = HALSTM25PC;
  
  SectorStorage = StorageManagerM.SectorStorage;
  Swap = StorageManagerM.Swap;
  Mount = StorageManagerM;
  StorageRemap = StorageManagerM;
  StorageManager = StorageManagerM;
  
  StorageManagerM.HALSTM25P -> HALSTM25PC.HALSTM25P[unique("HALSTM25P")];
  StorageManagerM.Leds -> LedsC;

}

--- NEW FILE: StorageManagerM.nc ---
// $Id: StorageManagerM.nc,v 1.1 2005/03/11 21:44:11 jwhui 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>
 */

module StorageManagerM {
  provides {
    interface SectorStorage[volume_t volume];
    interface SectorStorage as Swap[volume_t volume];
    interface Mount[volume_t volume];
    interface StdControl;
    interface StorageRemap[volume_t volume];
    interface StorageManager[volume_t volume];
  }
  uses {
    interface HALSTM25P;
    interface Leds;
  }
}

implementation {

  enum {
    NUM_VOLUMES = uniqueCount("StorageManager"),
  };

  enum {
    S_NEVER_USED,
    S_READY,
    S_MOUNT,
    S_WRITE,
    S_SWAP_WRITE,
    S_INIT_SWAP,
    S_COMMIT_SWAP,
  };

  uint8_t state;

  SectorTable sectorTable;
  volume_id_t volumeMap[NUM_VOLUMES];
  volume_t clientVolume;
  volume_id_t curVolumeId;

  uint8_t swapSector;
  bool swapSectorIsFree;

  stm25p_addr_t rwAddr;
  stm25p_addr_t rwLen;
  uint8_t* rwData;

  command result_t StdControl.init() {

    uint8_t i;
    
    state = S_NEVER_USED;

    swapSector = STM25P_NUM_SECTORS;
    swapSectorIsFree = TRUE;

    for ( i = 0; i < STM25P_NUM_SECTORS; i++ )
      sectorTable.sector[i].volumeId = STM25P_INVALID_VOLUME_ID;
    
    for ( i = 0; i < NUM_VOLUMES; i++ )
      volumeMap[i] = STM25P_INVALID_VOLUME_ID;
    
    return SUCCESS; 

  }

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

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

  bool admitRequest(volume_t volume) {
    if (state != S_READY)
      return FALSE;
    clientVolume = volume;
    return TRUE;
  }

  void signalDone(storage_result_t result) {

    uint8_t tmpState = state;
    state = S_READY;

    switch(tmpState) {
    case S_MOUNT: signal Mount.mountDone[clientVolume](result, volumeMap[clientVolume]); return;
    case S_WRITE: signal SectorStorage.writeDone[clientVolume](result); return;
    case S_SWAP_WRITE: signal Swap.writeDone[clientVolume](result); return;
    case S_INIT_SWAP: signal StorageManager.initSwapDone[clientVolume](result); return;
    case S_COMMIT_SWAP: signal StorageManager.commitSwapDone[clientVolume](result); return;
    }
    
  }

  uint16_t computeSectorTableCrc() {
    
    uint8_t* buf = (uint8_t*)&sectorTable;
    uint16_t crc;
    uint8_t i;
    
    for ( i = 0, crc = 0; i < sizeof(SectorTable) - 2; i++, buf++ )
      crc = crcByte(crc, *buf);
    
    return crc;

  }

  void actualMount() {

    volume_id_t i;

    storage_result_t result = STORAGE_FAIL;

    for ( i = 0; i < STM25P_NUM_SECTORS; i++ ) {
      if (sectorTable.sector[i].volumeId == curVolumeId) {
	volumeMap[clientVolume] = curVolumeId;
	result = STORAGE_OK;
	break;
      }
    }

    signalDone(result);

  }

  task void mount() {
    actualMount();
  }

  command result_t Mount.mount[volume_t volume](volume_id_t volumeID) {

    int16_t newestVersion;
    uint8_t newestSector;
    uint8_t i;

    if (state != S_READY && state != S_NEVER_USED)
      return FAIL;
    
    curVolumeId = volumeID;
    clientVolume = volume;

    // if already used, shortcut to checking metadata
    if (state == S_READY) {
      if (post mount() == SUCCESS) {
	state = S_MOUNT;
	return SUCCESS;
      }
      return FAIL;
    }

    // if never used, find newest sector table
    newestVersion = STM25P_INVALID_VERSION;
    newestSector = STM25P_NUM_SECTORS;
    for ( i = 0; i < STM25P_NUM_SECTORS; i++ ) {
      if (call HALSTM25P.read(STM25P_SECTOR_SIZE*i+STORAGE_BLOCK_SIZE, 
			      (uint8_t*)&sectorTable, sizeof(sectorTable)) == FAIL)
	return FAIL;
      if (sectorTable.version != STM25P_INVALID_VERSION
	  && !sectorTable.sector[i].isFixed
	  && sectorTable.crc == computeSectorTableCrc()
	  && ((sectorTable.version - newestVersion) > 0
	      || newestVersion == STM25P_INVALID_VERSION)) {
	newestVersion = sectorTable.version;
	newestSector = i;
      }
    }

    if (newestSector == STM25P_NUM_SECTORS)
      return FAIL;
    
    // searched all sectors, load newest table
    if (call HALSTM25P.read(STM25P_SECTOR_SIZE*newestSector+STORAGE_BLOCK_SIZE,
			    (uint8_t*)&sectorTable, sizeof(SectorTable)) == FAIL)
      return FAIL;


    // sector table loaded, find free sector for swap
    for ( i = 0; i < STM25P_NUM_SECTORS; i++ ) {
      if ( sectorTable.sector[i].volumeId == STM25P_INVALID_VOLUME_ID ) {
	swapSector = i;
	break;
      }
    }

    // continue with mount operation
    if (post mount() == SUCCESS) {
      state = S_MOUNT;
      return SUCCESS;
    }

    return FAIL;

  }

  stm25p_addr_t physicalAddr(volume_t volume, uint32_t volumeAddr) {

    stm25p_addr_t offset = volumeAddr % STORAGE_BLOCK_SIZE;
    uint8_t sector = volumeAddr / STORAGE_BLOCK_SIZE;
    volume_id_t i;

    for ( i = 0; i < STM25P_NUM_SECTORS; i++ ) {
      if (sectorTable.sector[i].volumeId == volumeMap[volume]
	  && sectorTable.sector[i].sectorId == sector)
	break;
    }

    if ( i == STM25P_NUM_SECTORS )
      return STM25P_INVALID_ADDR;
    
    return STM25P_SECTOR_SIZE*i + offset;    

  }

  command uint32_t StorageRemap.physicalAddr[volume_t volume](uint32_t volumeAddr) {

    if (admitRequest(volume) == FAIL)
      return FAIL;

    return physicalAddr(volume, volumeAddr);

  }

  command stm25p_addr_t StorageManager.getVolumeSize[volume_t volume]() {

    uint8_t maxSector;
    uint8_t i;
    
    if (state == S_NEVER_USED || state == S_MOUNT)
      return FAIL;
    
    for ( i = 0, maxSector = 0; i < STM25P_NUM_SECTORS; i++ ) {
      if (sectorTable.sector[i].volumeId == volumeMap[volume]
	  && sectorTable.sector[i].sectorId > maxSector)
	maxSector = sectorTable.sector[i].sectorId;
    }
     
    return STORAGE_BLOCK_SIZE * (maxSector+1);

  }

  command uint8_t StorageManager.initSwap[volume_t volume]() {

    if (admitRequest(volume) == FAIL)
      return FAIL;

    // check if swap is already in progress
    if (!swapSectorIsFree)
      return FAIL;
    
    state = S_INIT_SWAP;

    // erase new swap sector
    if (call HALSTM25P.sectorErase(STM25P_SECTOR_SIZE*swapSector) == FAIL) {
      state = S_READY;
      return FAIL;
    }
    
    swapSectorIsFree = FALSE;

    return SUCCESS;

  }

  command result_t StorageManager.commitSwap[volume_t volume](stm25p_addr_t addr) {

    uint8_t oldSector;
    uint8_t i;

    if (admitRequest(volume) == FAIL)
      return FAIL;
    
    if (swapSectorIsFree)
      return FAIL;

    // find sector to swap with
    oldSector = addr / STORAGE_BLOCK_SIZE;
    for ( i = 0; i < STM25P_NUM_SECTORS; i++ ) {
      if ( sectorTable.sector[i].volumeId == volumeMap[volume]
	   && sectorTable.sector[i].sectorId == oldSector ) {
	oldSector = i;
	break;
      }
    }

    if ( i == STM25P_NUM_SECTORS )
      return FAIL;
    
    state = S_COMMIT_SWAP;

    // if sector is fixed, just erase it
    if ( sectorTable.sector[oldSector].isFixed ) {
      if (call HALSTM25P.sectorErase(STM25P_SECTOR_SIZE*oldSector) == FAIL) {
	state = S_READY;
	return FAIL;
      }
      return SUCCESS;
    }

    // update sector table
    sectorTable.sector[swapSector] = sectorTable.sector[oldSector];
    sectorTable.sector[oldSector].volumeId = STM25P_INVALID_VOLUME_ID;
    do {
      sectorTable.version++;
    } while ( sectorTable.version == STM25P_INVALID_VERSION );
    sectorTable.crc = computeSectorTableCrc();

    // write new sector table
    rwAddr = STM25P_SECTOR_SIZE * swapSector + STORAGE_BLOCK_SIZE;
    if (call HALSTM25P.pageProgram(rwAddr, (uint8_t*)&sectorTable,
				   sizeof(sectorTable)) == FAIL) {
      state = S_READY;
      sectorTable.sector[oldSector] = sectorTable.sector[swapSector];
      sectorTable.sector[swapSector].volumeId = STM25P_INVALID_VOLUME_ID;
      return FAIL;
    }

    swapSector = oldSector;

    return SUCCESS;

  }

  stm25p_addr_t calcNumBytes(stm25p_addr_t addr) {

    stm25p_addr_t pageOffset = addr % STM25P_PAGE_SIZE;
    stm25p_addr_t numBytes = STM25P_PAGE_SIZE - pageOffset;
    
    if ( rwLen < numBytes )
      numBytes = rwLen;
    
    return numBytes;
    
  }

  command result_t SectorStorage.read[volume_t volume](stm25p_addr_t addr, uint8_t* data, stm25p_addr_t len) {

    if ( admitRequest(volume) == FAIL )
      return FAIL;

    return call HALSTM25P.read(physicalAddr(volume, addr), data, len);

  }
  
  command result_t SectorStorage.write[volume_t volume](stm25p_addr_t addr, uint8_t* data, stm25p_addr_t len) {

    if ( admitRequest(volume) == FAIL )
      return FAIL;

    rwData = data;
    rwLen = len;
    rwAddr = physicalAddr(volume, addr);
    if ( rwAddr == STM25P_INVALID_ADDR )
      return FAIL;

    state = S_WRITE;

    if (call HALSTM25P.pageProgram(rwAddr, data, calcNumBytes(rwAddr)) == FAIL) {
      state = S_READY;
      return FAIL;
    }

    return SUCCESS;

  }

  command result_t SectorStorage.computeCrc[volume_t volume](uint16_t* crcResult, uint16_t crc, stm25p_addr_t addr, stm25p_addr_t len) {

    if ( admitRequest(volume) == FAIL )
      return FAIL;

    return call HALSTM25P.computeCrc(crcResult, crc, physicalAddr(volume, addr), len);

  }

  command result_t Swap.read[volume_t volume](stm25p_addr_t addr, uint8_t* data, stm25p_addr_t len) {

    if ( admitRequest(volume) == FAIL || swapSectorIsFree )
      return FAIL;

    return call HALSTM25P.read(STM25P_SECTOR_SIZE*swapSector+addr, data, len);

  }

  command result_t Swap.write[volume_t volume](stm25p_addr_t addr, uint8_t* data, stm25p_addr_t len) {

    if ( admitRequest(volume) == FAIL || swapSectorIsFree )
      return FAIL;

    rwData = data;
    rwLen = len;
    rwAddr = STM25P_SECTOR_SIZE*swapSector + addr;
    state = S_SWAP_WRITE;

    return call HALSTM25P.pageProgram(rwAddr, data, calcNumBytes(rwAddr));

  }

  command result_t Swap.computeCrc[volume_t volume](uint16_t* crcResult, uint16_t crc, stm25p_addr_t addr, stm25p_addr_t len) {

    if ( admitRequest(volume) == FAIL || swapSectorIsFree )
      return FAIL;
    
    return call HALSTM25P.computeCrc(crcResult, crc, STM25P_SECTOR_SIZE*swapSector+addr, len);

  }

  event void HALSTM25P.pageProgramDone(result_t result) {

    stm25p_addr_t lastBytes;
    uint8_t oldSwapSector;

    if (state == S_COMMIT_SWAP) {

      if (result != STORAGE_OK) {
	oldSwapSector = rwAddr / STM25P_SECTOR_SIZE;
	sectorTable.sector[swapSector] = sectorTable.sector[oldSwapSector];
	sectorTable.sector[oldSwapSector].sectorId = STM25P_INVALID_VOLUME_ID;
	swapSector = oldSwapSector;
      }
      swapSectorIsFree = TRUE;
      signalDone(result);
      return;

    }

    if ( result != STORAGE_OK ) {
      signalDone(result);
      return;
    }
    
    lastBytes = calcNumBytes(rwAddr);

    rwAddr += lastBytes;
    rwData += lastBytes;
    rwLen -= lastBytes;

    if ( rwLen == 0 ) {
      signalDone(result);
      return;
    }
    
    if (call HALSTM25P.pageProgram(rwAddr, rwData, calcNumBytes(rwAddr)) == FAIL)
      signalDone(STORAGE_FAIL);
    
  }

  event void HALSTM25P.sectorEraseDone(result_t result) {
    if (state == S_COMMIT_SWAP)
      swapSectorIsFree = TRUE;
    signalDone(result);
  }

  event void HALSTM25P.bulkEraseDone(result_t result) { ; }
  event void HALSTM25P.readSRDone(result_t result, uint8_t value) { ; }
  event void HALSTM25P.writeSRDone(result_t result) { ; }

  default event void Mount.mountDone[volume_t volume](storage_result_t result, volume_id_t id) { ; }
  default event void SectorStorage.writeDone[volume_t volume](result_t result) { ; }
  default event void Swap.writeDone[volume_t volume](result_t result) { ; }
  default event void StorageManager.initSwapDone[volume_t volume](storage_result_t result) { ; }

}

--- NEW FILE: StorageRemap.nc ---
// $Id: StorageRemap.nc,v 1.1 2005/03/11 21:44:11 jwhui 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>
 */

interface StorageRemap {
  command uint32_t physicalAddr(uint32_t volumeAddr);
}

--- NEW FILE: Storage_chip.h ---
// $Id: Storage_chip.h,v 1.1 2005/03/11 21:44:11 jwhui Exp $

/*									tab:2
 * "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>
 */

#ifndef __STORAGE_CHIP_H__
#define __STORAGE_CHIP_H__

#include "HALSTM25P.h"

#endif



More information about the Tinyos-beta-commits mailing list