[Tinyos-2-commits] CVS: tinyos-2.x/tos/chips/pxa27x/p30 Flash.nc, NONE, 1.1.2.1 FlashC.nc, NONE, 1.1.2.1 HalP30C.nc, NONE, 1.1.2.1 HalP30P.nc, NONE, 1.1.2.1 HplP30.nc, NONE, 1.1.2.1 HplP30P.nc, NONE, 1.1.2.1 P30.h, NONE, 1.1.2.1 P30BlockC.nc, NONE, 1.1.2.1 P30BlockP.nc, NONE, 1.1.2.1 P30ConfigC.nc, NONE, 1.1.2.1 P30ConfigP.nc, NONE, 1.1.2.1 P30LogC.nc, NONE, 1.1.2.1 P30LogCircularP.nc, NONE, 1.1.2.1 P30LogP.nc, NONE, 1.1.2.1 Storage_chip.h, NONE, 1.1.2.1

Philip Buonadonna philipb at users.sourceforge.net
Tue Jul 25 18:40:13 PDT 2006


Update of /cvsroot/tinyos/tinyos-2.x/tos/chips/pxa27x/p30
In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv23691

Added Files:
      Tag: tinyos-2_0_devel-BRANCH
	Flash.nc FlashC.nc HalP30C.nc HalP30P.nc HplP30.nc HplP30P.nc 
	P30.h P30BlockC.nc P30BlockP.nc P30ConfigC.nc P30ConfigP.nc 
	P30LogC.nc P30LogCircularP.nc P30LogP.nc Storage_chip.h 
Log Message:
Initial add of P30 strataflash support to pxa27x chip series

--- NEW FILE: Flash.nc ---
/*									tab:4
 *  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.  By
 *  downloading, copying, installing or using the software you agree to
 *  this license.  If you do not agree to this license, do not download,
 *  install, copy or use the software.
 *
 *  Intel Open Source License 
 *
 *  Copyright (c) 2002 Intel Corporation 
 *  All rights reserved. 
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 * 
 *	Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *	Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *      Neither the name of the Intel Corporation nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *  PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE INTEL OR ITS
 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * 
 */
/**
 * Interface for writing and erasing in flash memory
 *
 * Author:		Josh Herbach
 * Revision:	1.0
 * Date:		09/02/2005
 */

interface Flash
{
  /**
   * Writes numBytes of the buffer data to the address in flash specified
   * by addr. This function will only set bits low for the bytes it is 
   * supposed to write to.If addr connot be written to for any reason returns
   * FAIL, otherwise returns SUCCESS.
   *
   * @returns SUCCESS or FAIL.
   */
  command error_t write(uint32_t addr, uint8_t* data, uint32_t numBytes);

  /**
   * Erases the block of flash that contains addr, setting all bits to 1.
   * If this function fails for any reason it will return FAIL, otherwise 
   * SUCCESS.
   *
   * @returns SUCCESS or FAIL.
   */
  command error_t erase(uint32_t addr);

  /**
   * Reads len number of bytes into buf, starting at addr. If addr
   * cannot be read for any reason returns FAIL, otherwise returns
   * SUCCESS.
  */
  command error_t read(uint32_t addr, uint8_t* buf, uint32_t len);
}




--- NEW FILE: FlashC.nc ---
/* 
 * Author:		Josh Herbach
 * Revision:	1.0
 * Date:		09/02/2005
 */

configuration FlashC {
  provides interface Flash;
}
implementation {
  components 
    Main,
    FlashM;

  Main.StdControl -> FlashM;
  Flash = FlashM;
}

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

/**
 * P30 Hal component
 * 
 * @author Kaisen Lin
 * @author Phil Buonadonna
 */

configuration HalP30C {
  provides interface Flash;
}

implementation {
  components HalP30P, HplP30P, MainC;

  Flash = HalP30P;

  MainC.SoftwareInit -> HalP30P;
  HalP30P.HplP30 -> HplP30P;
}

--- NEW FILE: HalP30P.nc ---
/* 
 * Author:		Josh Herbach
 * Revision:	1.0
 * Date:		09/02/2005
 */
module HalP30P {
  provides interface Init;
  provides interface Flash; //does not allow writing into FLASH_PROTECTED_REGION
  uses interface HplP30;
}
implementation {
  
#include <P30.h>

  enum {
    FLASH_STATE_READ_INACTIVE, 
    FLASH_STATE_PROGRAM,
    FLASH_STATE_ERASE,
    FLASH_STATE_READ_ACTIVE
  };

  uint8_t FlashPartitionState[FLASH_PARTITION_COUNT];
  uint8_t init = 0, programBufferSupported = 2, currBlock = 0;
  
  command error_t Init.init() {
    int i = 0;
    if(init != 0)
      return SUCCESS;
    init = 1;
    for(i = 0; i < FLASH_PARTITION_COUNT; i++) 
      FlashPartitionState[i] = FLASH_STATE_READ_INACTIVE;
    
    return SUCCESS;
  }
  
  uint16_t writeHelper(uint32_t addr, uint8_t* data, uint32_t numBytes,
		       uint8_t prebyte, uint8_t postbyte){
    uint32_t i = 0, j = 0, k = 0;
    error_t status;
    uint16_t buffer[FLASH_PROGRAM_BUFFER_SIZE];
    
    if(numBytes == 0)
      return FAIL;
    
    if(addr % 2 == 1){
      status = call HplP30.progWord(addr - 1, prebyte | (data[i] << 8));
      i++;
      if(status != SUCCESS)
	return FAIL;
    }
    
    if(addr % 2 == numBytes % 2){
      if(programBufferSupported == 1)
	for(; i < numBytes; i = k){
	  for(j = 0, k = i; k < numBytes && 
		j < FLASH_PROGRAM_BUFFER_SIZE; j++, k+=2)
	    buffer[j] = data[k] | (data[k + 1] << 8);
	  status = call HplP30.progBuffer(addr + i, buffer, j);
	  if(status != SUCCESS)
	    return FAIL;
	}
      else
	for(; i < numBytes; i+=2){
	  status = call HplP30.progWord(addr + i, (data[i + 1] << 8) | data[i]);
	  if(status != SUCCESS)
	    return FAIL;
	}
    }
    else{
      if(programBufferSupported == 1)
	for(; i < numBytes - 1; i = k){
	  for(j = 0, k = i; k < numBytes - 1 && 
		j < FLASH_PROGRAM_BUFFER_SIZE; j++, k+=2)
	    buffer[j] = data[k] | (data[k + 1] << 8);
	  status = call HplP30.progBuffer(addr + i, buffer, j);
	  if(status != SUCCESS)
	    return FAIL;
	}
      else
	for(; i < numBytes - 1; i+=2){
	  status = call HplP30.progWord(addr + i, (data[i + 1] << 8) | data[i]);
	  if(status != SUCCESS)
	    return FAIL;
	}
      status = call HplP30.progWord(addr + i, data[i] | (postbyte << 8));
      if(status != SUCCESS)
	return FAIL;
    }
    return SUCCESS;
  }
  
  void writeExitHelper(uint32_t addr, uint32_t numBytes){
    uint32_t i = 0;
    for(i = addr / FLASH_PARTITION_SIZE;
	i < (numBytes + addr) / FLASH_PARTITION_SIZE;
	i++)
      FlashPartitionState[i] = FLASH_STATE_READ_INACTIVE;
  }
  
  command error_t Flash.write(uint32_t addr, uint8_t* data, uint32_t numBytes) {
    uint32_t i;
    uint16_t status;
    uint8_t blocklen;
    uint32_t blockAddr = (addr / P30_BLOCK_SIZE) * P30_BLOCK_SIZE;
    
    if(addr + numBytes > 0x02000000) //not in the flash memory space
      return FAIL;
    if(addr < FLASH_PROTECTED_REGION)
      return FAIL;
    
    
    for(i = 0; i < FLASH_PARTITION_COUNT; i++)
      if(i != addr / FLASH_PARTITION_SIZE &&
	 FlashPartitionState[i] != FLASH_STATE_READ_INACTIVE &&
	 FlashPartitionState[i] != FLASH_STATE_READ_ACTIVE)
	return FAIL;
    
    
    for(i = addr / FLASH_PARTITION_SIZE;
	i < (numBytes + addr) / FLASH_PARTITION_SIZE;
	i++)
      if(FlashPartitionState[i] != FLASH_STATE_READ_INACTIVE)
	return FAIL;
    
    for(i = addr / FLASH_PARTITION_SIZE;
	i < (numBytes + addr) / FLASH_PARTITION_SIZE;
	i++)
      FlashPartitionState[i] = FLASH_STATE_PROGRAM;

    atomic{
      for(blocklen = 0, i = blockAddr;
	  i < addr + numBytes;
	  i += P30_BLOCK_SIZE, blocklen++)
	call HplP30.blkUnlock(i); //unlock(i);
      
      if(programBufferSupported == 2){
	uint16_t testBuf[1];
	
	if(addr % 2 == 0){
	  testBuf[0] = data[0] | ((*((uint8_t *)(addr + 1))) << 8);
	  status = call HplP30.progBuffer(addr, testBuf, 1);
	}
	else{
	  testBuf[0] = *((uint8_t *)(addr - 1)) | (data[0] << 8);
	  status = call HplP30.progBuffer(addr - 1, testBuf, 1);
	}      
	if(status != SUCCESS)
	  programBufferSupported = 0;
	else 
	  programBufferSupported = 1;
      }
    }
    if(blocklen == 1){
      atomic status = writeHelper(addr,data,numBytes,0xFF,0xFF);
      if(status == FAIL){
	writeExitHelper(addr, numBytes);
	return FAIL;
      }
    }
    else{
      uint32_t bytesLeft = numBytes;
      atomic status = writeHelper(addr,data, blockAddr + P30_BLOCK_SIZE - addr,0xFF,0xFF);
      if(status == FAIL){
	writeExitHelper(addr, numBytes);
	return FAIL;
      }
      bytesLeft = numBytes - (P30_BLOCK_SIZE - (addr - blockAddr));
      for(i = 1; i < blocklen - 1; i++){
	atomic status = writeHelper(blockAddr + i * P30_BLOCK_SIZE, (uint8_t *)(data + numBytes - bytesLeft),
				    P30_BLOCK_SIZE,0xFF,0xFF);
	bytesLeft -= P30_BLOCK_SIZE;
	if(status == FAIL){
	  writeExitHelper(addr, numBytes);
	  return FAIL;
	}
      }
      atomic status = writeHelper(blockAddr + i * P30_BLOCK_SIZE, data + (numBytes - bytesLeft), bytesLeft, 0xFF,0xFF);
      if(status == FAIL){
	writeExitHelper(addr, numBytes);
	return FAIL;
      }
    }
    
    writeExitHelper(addr, numBytes);
    return SUCCESS;
  }
  
  command error_t Flash.erase(uint32_t addr){
    uint16_t status, i;
    uint32_t j;
    
    if(addr > 0x02000000) //not in the flash memory space
      return FAIL;
    if(addr < FLASH_PROTECTED_REGION)
      return FAIL;
    
    addr = (addr / P30_BLOCK_SIZE) * P30_BLOCK_SIZE;
    
    for(i = 0; i < FLASH_PARTITION_COUNT; i++)
      if(i != addr / FLASH_PARTITION_SIZE &&
	 FlashPartitionState[i] != FLASH_STATE_READ_INACTIVE &&
	 FlashPartitionState[i] != FLASH_STATE_READ_ACTIVE)
	return FAIL;
    
    if(FlashPartitionState[addr / FLASH_PARTITION_SIZE] != FLASH_STATE_READ_INACTIVE)
      return FAIL;
    
    FlashPartitionState[addr / FLASH_PARTITION_SIZE] = FLASH_STATE_ERASE;
    
    for(j = 0; j < P30_BLOCK_SIZE; j++){
      uint32_t tempCheck = *(uint32_t *)(addr + j);
      if(tempCheck != 0xFFFFFFFF)
	break;
      if(j == P30_BLOCK_SIZE - 1){
	FlashPartitionState[addr / FLASH_PARTITION_SIZE] = FLASH_STATE_READ_INACTIVE;
	return SUCCESS;
      }
    }
    atomic{
      call HplP30.blkUnlock(addr);
      //      status = eraseFlash(addr);
      status = call HplP30.blkErase(addr);
    }
    FlashPartitionState[addr / FLASH_PARTITION_SIZE] = FLASH_STATE_READ_INACTIVE;
    if(status != SUCCESS)
      return FAIL;
    
    return SUCCESS;
  }

  // WARNING: Check the endien of this
  command error_t Flash.read(uint32_t addr, uint8_t* buf, uint32_t len) {
    error_t status;

    uint8_t databyte;
    /*
    uint16_t dataword;
    
    while(len > 1) {
      atomic {
	status = call HplP30.readWordBurst(addr, &dataword);
      }
      if(status != SUCCESS)
	return FAIL;
      
      *((uint16_t*) buf) = dataword;

      addr += 2;
      buf += 2;
      len -= 2;
    }

    if(len == 1) {
      atomic {
	status = call HplP30.readWordBurst(addr, &dataword);
      }
      if(status != SUCCESS)
	return FAIL;

      *buf = (uint8_t) dataword;
    }
    */

    while(len > 0) {
      atomic {
	status = call HplP30.readByteBurst(addr, &databyte);
      }
      if(status != SUCCESS)
	return FAIL;
      
      *buf = databyte;

      addr += 1;
      buf += 1;
      len -= 1;
    }

    return SUCCESS;
  }
}

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

interface HplP30 {

  async command error_t progWord(uint32_t addr, uint16_t word);
  async command error_t progBuffer(uint32_t addr, uint16_t *data, uint8_t len);
  async command error_t blkErase(uint32_t blkaddr);
  async command error_t blkLock(uint32_t blkaddr);
  async command error_t blkUnlock(uint32_t blkaddr);

  async command error_t readByteBurst(uint32_t addr, uint8_t* bytex);
  async command error_t readWordBurst(uint32_t addr, uint16_t* word);
}

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

implementation {

  volatile uint16_t * devBaseAddress = (uint16_t *)(0x0);

  async command error_t HplP30.progWord(uint32_t addr, uint16_t word) {
    volatile uint16_t *blkAddress = (uint16_t *)addr;
    uint32_t result;

    *devBaseAddress = P30_READ_CLRSTATUS;
    *blkAddress = P30_WRITE_WORDPRGSETUP;
    *blkAddress = word;

    do {
      result = *blkAddress;
    } while ((result & P30_SR_DWS) == 0);

    *blkAddress = P30_READ_READARRAY;

    if (result & (P30_SR_PS | P30_SR_VPPS | P30_SR_BLS)) {
      return FAIL;
    }

    return SUCCESS;

  }

  async command error_t HplP30.progBuffer(uint32_t addr, uint16_t *data, uint8_t len) {
    volatile uint16_t *blkAddress = (uint16_t *)addr;
    uint32_t i,result;
    error_t error = SUCCESS;

    if (len <= 0) {
      error = EINVAL;
      goto done;
    }

    *devBaseAddress = P30_READ_CLRSTATUS;
    *blkAddress = P30_WRITE_BUFPRG;

    result = *blkAddress;
    if ((result & P30_SR_DWS) == 0) {
      error = FAIL;
      goto cleanup;
    }

    *blkAddress = len-1;
    
    for (i=0;i<len;i++) {
      blkAddress[i] = data[i];
    }
    
    *blkAddress = P30_WRITE_BUFPRGCONFIRM;

    do {
      result = *blkAddress;
    } while ((result & P30_SR_DWS) == 0);

    if (result & (P30_SR_PS | P30_SR_VPPS)) {
      error = FAIL;
      goto done;
    }
  cleanup:
    *blkAddress = P30_READ_READARRAY;
  done:
    return error;

  }

  async command error_t HplP30.blkErase(uint32_t blkaddr) {
    volatile uint16_t *blkAddress = (uint16_t *)blkaddr;
    uint32_t result;

    *devBaseAddress = P30_READ_CLRSTATUS;
    *blkAddress = P30_ERASE_BLKSETUP;
    *blkAddress = P30_ERASE_BLKCONFIRM;

    do {
      result = *blkAddress;
    } while ((result & P30_SR_DWS) == 0);

    *blkAddress = P30_READ_READARRAY;

    if (result & (P30_SR_ES | P30_SR_VPPS | P30_SR_BLS)) {
      return FAIL;
    }

    return SUCCESS;

  }

  async command error_t HplP30.blkLock(uint32_t blkaddr) {
    volatile uint16_t *blkAddress = (uint16_t*) blkaddr;

    asm volatile (
		  ".align 5\n\t"
		  "strh %0,[%3]\n\t"
		  "strh %1,[%3]\n\t"
		  "strh %2,[%3]\n\t"
		  : 
		  :"r" (P30_LOCK_SETUP), 
		  "r" (P30_LOCK_LOCK), 
		  "r" (P30_READ_READARRAY),
		  "r" (blkaddr)
		  );

    return SUCCESS;
  }

  async command error_t HplP30.blkUnlock(uint32_t blkaddr) {

    asm volatile (
		  ".align 5\n\t"
		  "strh %0,[%3]\n\t"
		  "strh %1,[%3]\n\t"
		  "strh %2,[%3]\n\t"
		  : 
		  : "r" (P30_LOCK_SETUP), 
		  "r" (P30_LOCK_UNLOCK), 
		  "r" (P30_READ_READARRAY),
		  "r" (blkaddr)
		  );

    return SUCCESS;

  }

  /* THIS FUNCTION IS UNTESTED, USE READBYTEBURST FOR NOW */
  async command error_t HplP30.readWordBurst(uint32_t addr, uint16_t* word) {
    volatile uint16_t *blkAddress = (uint16_t *)addr;
    *word = *blkAddress;
    return SUCCESS;
  }

  async command error_t HplP30.readByteBurst(uint32_t addr, uint8_t* bytex) {
    volatile uint8_t *blkAddress = (uint8_t *)addr;
    *bytex = *blkAddress;
    return SUCCESS;
  }

}

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

#ifndef _P30_H
#define _P30_H

#define P30_READ_READARRAY	(0x00FF)
#define P30_READ_RSR		(0x0070)
#define P30_READ_RCR		(0x0090)
#define P30_READ_QUERY		(0x0098)
#define P30_READ_CLRSTATUS	(0x0050)

#define P30_WRITE_WORDPRGSETUP	(0x0040)
#define P30_WRITE_ALTWORDPRGSETUP (0x0010)
#define P30_WRITE_BUFPRG	(0x00E8)
#define P30_WRITE_BUFPRGCONFIRM (0x00D0)
#define P30_WRITE_BEFPSETUP	(0x0080)
#define P30_WRITE_BEFPCONFIRM	(0x00D0)

#define P30_ERASE_BLKSETUP	(0x0020)
#define P30_ERASE_BLKCONFIRM	(0x00D0)

#define P30_SUSPEND_SUSPEND	(0x00B0)
#define P30_SUSPEND_RESUME	(0x00D0)

#define P30_LOCK_SETUP		(0x0060)
#define P30_LOCK_LOCK		(0x0001)
#define P30_LOCK_LOCKDOWN	(0x002F)
#define P30_LOCK_UNLOCK		(0x00D0)

#define P30_PROT_PSRSETUP	(0x00C0)

#define P30_CONFIG_RCRSETUP	(0x0060)
#define P30_CONFIG_RCR		(0x0003)

#define P30_SR_DWS		(1 << 7)
#define P30_SR_ESS		(1 << 6)
#define P30_SR_ES		(1 << 5)
#define P30_SR_PS		(1 << 4)
#define P30_SR_VPPS		(1 << 3)
#define P30_SR_PSS		(1 << 2)
#define P30_SR_BLS		(1 << 1)
#define P30_SR_BWS		(1 << 0)

#define P30_REGION_SIZE (0x100000)
#define P30_BLOCK_SIZE	(0x20000)

typedef struct p30_volume_info_t {
  uint8_t base; // base block
  uint8_t size; // num blocks
} p30_volume_info_t;

#define FLASH_PARTITION_COUNT 16
#define FLASH_PARTITION_SIZE 0x200000
#define FLASH_PROTECTED_REGION 0x00200000
#define FLASH_PROGRAM_BUFFER_SIZE 32
  //#define FLASH_NOT_SUPPORTED 0x100

#endif /* _P30_H */

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

implementation {
  components P30BlockP;
  P30BlockP = Write;
  P30BlockP = Read;

  components HalP30C;
  P30BlockP.Flash -> HalP30C;
}

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

module P30BlockP {
  provides interface BlockRead as Read[ storage_volume_t block ];
  provides interface BlockWrite as Write[ storage_volume_t block ];

  uses interface Leds;
  uses interface Flash;
}

implementation {
  typedef enum {
    S_IDLE,
    S_READ,
    S_WRITE,
    S_ERASE,
    S_CRC,
    S_COMMIT,
    S_VERIFY,
  } p30_block_state_t;
  norace p30_block_state_t m_state = S_IDLE;
  storage_volume_t clientId = 0xff;
  storage_addr_t clientAddr;
  void* clientBuf;
  storage_len_t clientLen;
  error_t clientResult;

  /*
   * This is a helper function to translate from the client address
   * space to the underlying HalP30 address space. This is necessary
   * because HAL provides a flat 32MB interface.
   */
  uint32_t xlateAddr(storage_volume_t b, storage_addr_t addr) {
    return P30_VMAP[b].base * FLASH_PARTITION_SIZE + addr;
  }

  task void signalDoneTask() {
    switch(m_state) {
    case S_WRITE:
      m_state = S_IDLE;
      signal Write.writeDone[clientId](clientAddr, clientBuf, clientLen, clientResult);
      break;
   case S_COMMIT:
      m_state = S_IDLE;
      signal Write.commitDone[clientId](SUCCESS);
      break;
    case S_ERASE:
      m_state = S_IDLE;
      signal Write.eraseDone[clientId](clientResult);
      break;
   case S_READ:
      m_state = S_IDLE;
      signal Read.readDone[clientId](clientAddr, clientBuf, clientLen, clientResult);
      break;
   case S_VERIFY:
      m_state = S_IDLE;
      signal Read.verifyDone[clientId](SUCCESS);
      break;
    default:
      break;
    }
  }

  /*
   * Translate the address to a physical flash address and do the
   * write.
   */
  command error_t Write.write[ storage_volume_t b ]( storage_addr_t addr, 
						    void* buf, 
						    storage_len_t len ) {
    uint32_t physAddr;

    if(m_state != S_IDLE)
      return EBUSY;

    // error check
    if(addr + len > P30_VMAP[b].size * FLASH_PARTITION_SIZE)
      return EINVAL;

    clientId = b;
    clientAddr = addr;
    clientBuf = buf;
    clientLen = len;

    m_state = S_WRITE;

    physAddr = xlateAddr(b, addr);

    clientResult = call Flash.write(physAddr, (uint8_t*) buf, len);

    post signalDoneTask();
    return SUCCESS;
  }
  
  /*
   * Commit doesn't really do anything because Intel PXA is
   * write-through.
   */
  command error_t Write.commit[ storage_volume_t b ]() {

    m_state = S_COMMIT;
    clientId = b;

    post signalDoneTask();
    return SUCCESS;
  }
  
  /*
   * Because each 2MB partition is divided into 128k erasable pieces,
   * we must go through and erase all of them.
   */
  command error_t Write.erase[ storage_volume_t b ]() {
   uint32_t physAddr;
   uint32_t blocks;

    if(m_state != S_IDLE)
      return EBUSY;

    clientId = b;

    m_state = S_ERASE;
    physAddr = xlateAddr(b,0);
    for(blocks = ((P30_VMAP[b].size)*FLASH_PARTITION_SIZE)/P30_BLOCK_SIZE;
	blocks > 0;
	blocks--) {
      clientResult = call Flash.erase(physAddr);
      if(clientResult != SUCCESS)
	break;
      physAddr += P30_BLOCK_SIZE;
    }

    post signalDoneTask();
    return SUCCESS;
  }

  /*
   * Translate the address to a physical flash address and do the
   * read.
   */
  command error_t Read.read[ storage_volume_t b ]( storage_addr_t addr,
						  void* buf,
						  storage_len_t len ) {
   uint32_t physAddr;

    if(m_state != S_IDLE)
      return FAIL;

    clientId = b;
    clientAddr = addr;
    clientBuf = buf;
    clientLen = len;

    m_state = S_READ;
    physAddr = xlateAddr(b,addr);

    call Flash.read((uint32_t) physAddr, (uint8_t*) buf, (uint32_t) len);

    post signalDoneTask();
    return SUCCESS;
  }
  
  command error_t Read.verify[ storage_volume_t b ]() {

    m_state = S_VERIFY;
    clientId = b;

    post signalDoneTask();
    return SUCCESS;
  }
  
  command error_t Read.computeCrc[ storage_volume_t b ]( storage_addr_t addr,
							storage_len_t len,
							uint16_t crc) {
    m_state = S_CRC;
    clientId = b;

    post signalDoneTask();
    return SUCCESS;
  }

  command storage_len_t Read.getSize[ storage_volume_t b]() {
    return P30_VMAP[b].size * FLASH_PARTITION_SIZE;
  }

  default event void Write.writeDone[ storage_volume_t b ]( storage_addr_t addr, void* buf, storage_len_t len, error_t error ) {}
  default event void Write.eraseDone[ storage_volume_t b ]( error_t error ) {}
  default event void Write.commitDone[ storage_volume_t b ]( error_t error ) {}

  default event void Read.readDone[ storage_volume_t b ]( storage_addr_t addr, void* buf, storage_len_t len, error_t error ) {}
  default event void Read.computeCrcDone[ storage_volume_t b ]( storage_addr_t addr, storage_len_t len, uint16_t crc, error_t error ) {}
  default event void Read.verifyDone[ storage_volume_t b ]( error_t error ) {}
}

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

implementation {
  components P30ConfigP, MainC;
  ConfigStorage = P30ConfigP.Config;
  Mount = P30ConfigP.Mount;

  components HalP30C;
  P30ConfigP.Flash -> HalP30C;
}

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

module P30ConfigP {
  provides interface ConfigStorage as Config[ storage_volume_t v ];
  provides interface Mount[ storage_volume_t v ];

  uses interface Flash;
  uses interface Leds;
}

implementation {
  /*
   * These are some macros for convenience. Essentially it is cutting
   * a 2MB chunk into a two pieces. The size of the two pieces is
   * hardcoded by C_PARTITION_sIZE. It must be a multiple of
   * P30_BLOCK_SIZE because that is the erasable size. The bigger you
   * make the C_PARTITION_SIZE, the longer commits will take because
   * it must erase all the blocks inside. On the other hand, a larger
   * C_PARTITION_SIZE will give you a larger address space. v is the
   * parameterized interface that is used in the context of these
   * macros.
   */
#define C_PARTITION_SIZE (P30_BLOCK_SIZE*1)
#define C_PARTITION_0 (P30_VMAP[v].base * FLASH_PARTITION_SIZE)
#define C_PARTITION_1 (P30_VMAP[v].base * FLASH_PARTITION_SIZE + C_PARTITION_SIZE)
  typedef uint32_t version_t;

  enum {
    /*
     * WARNING: AT45DB has a RAM buffer that allows writes to occur
     * without actually writing to flash. We simulate this because it
     * makes rewrites a lot simpler. However, this essentially takes
     * RAM overhead. However, Configstores are relatively small and
     * the Intel PXA has a lot of main memory, so we do it anyway.
     */
    BUFFER_SIZE = 2048, 
    INVALID_VERSION = 0xFFFFFFFF,
    NUM_VOLS = _V_NUMVOLS_, //uniqueCount( "pxa27xp30.Volume" ),
  };
  
  typedef enum {
    S_IDLE,
    S_MOUNT,
    S_READ,
    S_WRITE,
    S_COMMIT,
  } p30_config_state_t;
  norace p30_config_state_t m_state = S_IDLE;

  /*
   * Each instantiation of a Configstore must keep certain state. This
   * includes the current version of the page and the active address
   * within that page since we are splitting it into two pieces. Each
   * Configstore must also have its own RAM buffer for concurrent
   * operations.
   */ 
  uint32_t currentVersion[NUM_VOLS];
  uint32_t activeBaseAddr[NUM_VOLS];
  uint8_t workBuf[BUFFER_SIZE*NUM_VOLS];

  storage_volume_t clientId = 0xff;
  storage_addr_t clientAddr;
  void* clientBuf;
  storage_len_t clientLen;
  error_t clientResult;

  task void signalDoneTask() {
    switch(m_state) {
    case S_MOUNT:
      m_state = S_IDLE;
      signal Mount.mountDone[clientId](clientResult);
      break;
    case S_WRITE:
      m_state = S_IDLE;
      signal Config.writeDone[clientId](clientAddr, clientBuf, clientLen, clientResult);
      break;
    case S_COMMIT:
      m_state = S_IDLE;
      signal Config.commitDone[clientId](SUCCESS);
      break;
    case S_READ:
      m_state = S_IDLE;
      signal Config.readDone[clientId](clientAddr, clientBuf, clientLen, clientResult);
      break;
    default:
      break;
    }
  }

  /* 
   * Erase a config partition. It may be more than one P30 block size,
   * so erase multiple times.
   */
  void eraseConfigPartition(uint32_t base) {
    uint32_t blocks;
    
    for(blocks = C_PARTITION_SIZE / P30_BLOCK_SIZE;
	blocks > 0;
	blocks--) {
      call Flash.erase(base);
      base += P30_BLOCK_SIZE;
    }
  }

  /*
   * Read the data directly from the RAM buffer into the client
   * buffer... Might be read from Flash depending on semantics
   */
  command error_t Config.read[storage_volume_t v](storage_addr_t addr,
							  void* buf,
							  storage_len_t len) {
    uint32_t i;

    clientId = v;
    clientAddr = addr;
    clientBuf = buf;
    clientLen = len;

    m_state = S_READ;

    /*
    for(i = addr; i < addr + len; i++) {
      ((uint8_t*)buf)[i-addr] = workBuf[(v*BUFFER_SIZE)+i];
    }
    */
    call Flash.read(activeBaseAddr[v] + addr,
		    (uint8_t*) buf,
		    len);
    
    post signalDoneTask();
    
    return SUCCESS;
  }

  /*
   * Writes the client data into the given address in the RAM
   * buffer. Data is not actually written to flash until the user
   * commits.
   */
  command error_t Config.write[storage_volume_t v](storage_addr_t addr,
							   void* buf,
							   storage_len_t len) {
    uint32_t i;

    clientId = v;
    clientAddr = addr;
    clientBuf = buf;
    clientLen = len;

    // error check
    if(addr + len > BUFFER_SIZE)
      return FAIL; // out of my artificial bounds

    m_state = S_WRITE;

    for(i = addr; i < addr + len; i++)
      workBuf[(v*BUFFER_SIZE)+i] = ((uint8_t*)buf)[i-addr];

    clientResult = SUCCESS;
    post signalDoneTask();
    return SUCCESS;
  }

  /*
   * Determine which partition to write to based on the current one
   * that is active. Also update the version number. Version numbers
   * are 0, 1, 2, or 3 and wraps around. Write the RAM buffer out
   * first BEFORE writing the the new version number. After the
   * version number is written, the active config is now atomically
   * switched. Then update any other in memory metadata.
   */
  command error_t Config.commit[storage_volume_t v]() {
    uint32_t destBaseAddr;

    if(activeBaseAddr[v] == C_PARTITION_0)
      destBaseAddr = C_PARTITION_1;
    else
      destBaseAddr = C_PARTITION_0;

    m_state = S_COMMIT;

    clientId = v;
    clientResult = SUCCESS;

    currentVersion[v] = (currentVersion[v] + 1) % 4;

    // erase target flash area before writing to it
    eraseConfigPartition(destBaseAddr);

    // write RAM buffer out
    call Flash.write(destBaseAddr,
		     (uint8_t*) &workBuf[v*BUFFER_SIZE],
		     BUFFER_SIZE);

    call Flash.write(destBaseAddr + C_PARTITION_SIZE - sizeof(version_t),
		     (uint8_t*) &currentVersion[v],
		     sizeof(version_t));

    activeBaseAddr[v] = destBaseAddr;

    post signalDoneTask();
    return SUCCESS;
  }

  /*
   * The only metadata that needs to be saved is a version
   * number. Thus you get the whole partition minus the version number
   * in terms of space.
   */
  command storage_len_t Config.getSize[storage_volume_t v]() {
    return C_PARTITION_SIZE - sizeof(version_t);
  }

  command bool Config.valid[storage_volume_t v]() {
    return TRUE;
  }

  /*
   * When a Configstore is mounted, it must do some initial
   * book-keeping work. It first reads from the two pieces two
   * determine, which one is the actual active one. Afterwards, we
   * read from flash into the RAM buffer or else subsequent reads will
   * not work.
   */
  command error_t Mount.mount[storage_volume_t v]() {
    version_t v0;
    version_t v1;

    m_state = S_MOUNT;
    clientResult = SUCCESS;
    clientId = v;

    currentVersion[v] = INVALID_VERSION;

    // read version #s from both sectors and determine new one
    // pick among 0 1 2 3 FFFF
    call Flash.read(C_PARTITION_0 + C_PARTITION_SIZE - sizeof(version_t),
		    (uint8_t*)&v0, sizeof(version_t));
    call Flash.read(C_PARTITION_1 + C_PARTITION_SIZE - sizeof(version_t),
		    (uint8_t*)&v1, sizeof(version_t));

    // this logic in this could probably be simplified
    if(v0 == INVALID_VERSION && v1 == INVALID_VERSION) {
      // clean partition
      activeBaseAddr[v] = C_PARTITION_0;
      currentVersion[v] = 0;
    }
    else if(v1 == INVALID_VERSION) {
      // use v0
      activeBaseAddr[v] = C_PARTITION_0;
      currentVersion[v] = v0;
    }
    else if(v0 == INVALID_VERSION) {
      // use v1
      activeBaseAddr[v] = C_PARTITION_1;
      currentVersion[v] = v1;
    }
    else if((v0 + 1) % 4 == v1) {
      // use v1
      activeBaseAddr[v] = C_PARTITION_1;
      currentVersion[v] = v1;
    }
    else if((v1 + 1) % 4 == v0) {
      // use v0
      activeBaseAddr[v] = C_PARTITION_0;
      currentVersion[v] = v0;
    }
    else {
      // corrupted? erase both, might want to improve this later
      eraseConfigPartition(C_PARTITION_0);
      eraseConfigPartition(C_PARTITION_1);
      currentVersion[v] = 0;
    }

    // read into RAM buffer
    call Flash.read(activeBaseAddr[v], (uint8_t*)&workBuf[v*BUFFER_SIZE], BUFFER_SIZE);

    post signalDoneTask();
    return SUCCESS;
  }

  default event void Config.readDone[storage_volume_t v](storage_addr_t addr, void* buf, storage_len_t len, error_t error) {}
  default event void Config.writeDone[storage_volume_t v](storage_addr_t addr, void* buf, storage_len_t len, error_t error) {}
  default event void Config.commitDone[storage_volume_t v](error_t error) {}
  default event void Mount.mountDone[storage_volume_t v](error_t error) {}
}


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

  provides interface LogWrite as Write[ storage_volume_t volume ];
  provides interface LogRead as Read[ storage_volume_t volume ];

  uses interface Get<bool> as Circular[ storage_volume_t block ];
}

implementation {
  components P30LogP;

  P30LogP = Write;
  P30LogP = Read;

  P30LogP = Circular;

  components HalP30C;
  P30LogP.Flash -> HalP30C;
}

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

  provides interface Get<bool> as Circular;

}

implementation {
  
  command bool Circular.get() {
    return IS_CIRCULAR;
  }

}

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

module P30LogP {
  provides interface LogRead as Read[ storage_volume_t block ];
  provides interface LogWrite as Write[ storage_volume_t block ];

  uses interface Leds;
  uses interface Flash;
  uses interface Get<bool> as Circular[ storage_volume_t block ];
}

implementation {

#define SEEK_BEGINNING (0x0)
#define SEEK_EOL (0xFFFFFFFF)
#define L_BASE_BLOCK(_x) (P30_VMAP[_x].base * FLASH_PARTITION_SIZE)
#define L_PARTITIONS(_x) ((P30_VMAP[_x].size * FLASH_PARTITION_SIZE) / P30_BLOCK_SIZE)
#define L_FULL_RECORD_SIZE (sizeof(record_data_t) + sizeof(record_meta_t))
#define L_RECORD_DATA_SIZE 256
#define L_MAX_RECORDS_PER_BLOCK (P30_BLOCK_SIZE / L_FULL_RECORD_SIZE) // page meta counts as one record
  // _a = blockId (from parameterized interface), _b = page, _c = record
#define L_RAW_OFFSET(_a,_b,_c) (L_BASE_BLOCK(_a) + (_b * P30_BLOCK_SIZE) + (_c * L_FULL_RECORD_SIZE))

  enum {
    INVALID_VERSION = 0xFFFFFFFF,
    NUM_VOLS = _V_NUMVOLS_, //uniqueCount("pxa27xp30.Volume"),
  };

  enum {
    PAGE_START = 0x0000,
    PAGE_USED = 0xFFF0,
    PAGE_AVAILABLE = 0xFFFF,
  };
  typedef struct page_meta_t {
    uint16_t header;
  } page_meta_t;

  enum {
    RECORD_VALID = 0x0000,
    RECORD_INVALID = 0xFFF0,
    RECORD_EMPTY = 0xFFFF,
  };
  typedef struct record_meta_t {
    uint16_t status;
    uint16_t length;
  } record_meta_t;
  typedef struct record_data_t {
    uint8_t data[L_RECORD_DATA_SIZE];
  } record_data_t;

  typedef enum {
    S_IDLE,
    S_READ,
    S_APPEND,
    S_SYNC,
    S_ERASE,
    S_SEEK,
  } p30_log_state_t;
  norace p30_log_state_t m_state = S_IDLE;
  storage_volume_t clientId = 0xff;
  void* clientBuf;
  storage_len_t clientLen;
  error_t clientResult;

  uint32_t firstBlock[NUM_VOLS]; // 0-15 for 2 MB
  uint32_t lastBlock[NUM_VOLS]; // 0-15 for 2 MB
  uint32_t nextFreeRecord[NUM_VOLS]; // 0-X depending on data size
  storage_cookie_t readCookieOffset[NUM_VOLS]; // this is a raw offset

  /* This shuffles all the blocks when we run out of space. We have to
   * do it in a special order so crash recovery is possible. We also
   * have to write special bytes so we can rewrite to areas without
   * doing a complete erase.
   */
  void shuffleBlocks(storage_volume_t block) {
    page_meta_t pageMeta;
    uint32_t pageCounter;
    // 1. set the last block to USED, if it's already USED or START, then no effect
    pageMeta.header = PAGE_USED;
    call Flash.write(L_RAW_OFFSET(block, lastBlock[block], 0),
		     (uint8_t*) &pageMeta,
		     sizeof(page_meta_t));
    // 2. if lastBlock + 1 is free, then set it as last block and the first record is free
    pageCounter = (lastBlock[block] + 1) % L_PARTITIONS(block);
    call Flash.read(L_RAW_OFFSET(block, pageCounter, 0),
		    (uint8_t*) &pageMeta,
		    sizeof(page_meta_t));
    if(pageMeta.header == PAGE_AVAILABLE) {
      nextFreeRecord[block] = 1;
      lastBlock[block] = pageCounter;
    }
    else {
      call Flash.erase(L_RAW_OFFSET(block, firstBlock[block], 0));
      pageCounter = (firstBlock[block] + 1) % L_PARTITIONS(block);
      pageMeta.header = PAGE_START;
      call Flash.write(L_RAW_OFFSET(block, pageCounter, 0),
		       (uint8_t*) &pageMeta,
		       sizeof(page_meta_t));
      nextFreeRecord[block] = 1;
      lastBlock[block] = firstBlock[block];
      firstBlock[block] = pageCounter;
    }
  }

  /*
   * Converts a cookie to a page/record/offset tuple
   */
  void cookieToTuple(uint32_t cookie, storage_volume_t block,
		     uint32_t *page, uint32_t *record, uint32_t *offset) {

    uint32_t mypage;
    uint32_t myrecord;
    uint32_t myoffset;

    mypage = (cookie - L_BASE_BLOCK(block)) / P30_BLOCK_SIZE;
    cookie = (cookie - L_BASE_BLOCK(block)) % P30_BLOCK_SIZE;
    myrecord = cookie / L_FULL_RECORD_SIZE;
    myoffset = (cookie % L_FULL_RECORD_SIZE) - sizeof(record_meta_t);

    *page = mypage;
    *record = myrecord;
    *offset = myoffset;
  }

  /*
   * Ideally, Logstorage would require a mount too, but it doesn't so
   * it's a total hack. Before any operation, we have to check if a
   * mount occurred. Mount initializes the your logblock.
   */
  uint8_t mountBits[NUM_VOLS];
  void myMount(storage_volume_t block) {
    page_meta_t pageMeta;
    record_meta_t recordMeta;
    uint32_t pageCounter;
    uint32_t recordCounter;

    uint32_t freePages = 0;

    if(mountBits[block] != 0)
      return;

    // scan all 128k pages for page meta

    // annoying corner case of all free pages, write the first page as START
    for(pageCounter = 0; pageCounter < L_PARTITIONS(block); pageCounter++) {
      call Flash.read(L_RAW_OFFSET(block, pageCounter, 0),
		      (uint8_t*)&pageMeta,
		      sizeof(page_meta_t));
      if(pageMeta.header == PAGE_AVAILABLE)
	freePages++;
    }
    if(freePages == L_PARTITIONS(block)) {
      pageMeta.header = PAGE_START;
      call Flash.write(L_RAW_OFFSET(block, 0, 0), (uint8_t*) &pageMeta, sizeof(page_meta_t));
    }

    // if we find a START page, then we are done
    for(pageCounter = 0; pageCounter < L_PARTITIONS(block); pageCounter++) {
      call Flash.read(L_RAW_OFFSET(block, pageCounter, 0),
		      (uint8_t*)&pageMeta,
		      sizeof(page_meta_t));
      if(pageMeta.header == PAGE_START) {
	firstBlock[block] = pageCounter;
	break;
      }
    }
    // if we didn't find a START page, first page is right after AVAILABLE
    if(pageCounter == L_PARTITIONS(block)) {
      for(pageCounter = 0; pageCounter < L_PARTITIONS(block); pageCounter++) {
	call Flash.read(L_RAW_OFFSET(block, pageCounter, 0),
			(uint8_t*)&pageMeta,
			sizeof(page_meta_t));
	if(pageMeta.header == PAGE_AVAILABLE) {
	  pageCounter = (pageCounter + 1) % L_PARTITIONS(block);
	  firstBlock[block] = pageCounter;
	  // mark that block as a START block
	  pageMeta.header = PAGE_START;
	  call Flash.write(L_RAW_OFFSET(block, pageCounter, 0),
			   (uint8_t*) &pageMeta,
			   sizeof(page_meta_t));
	  break;
	}
      }
    }
    // now we scan for next free record location
    pageCounter = firstBlock[block];
    for(recordCounter = 1; recordCounter < L_MAX_RECORDS_PER_BLOCK; recordCounter++) {
      call Flash.read(L_RAW_OFFSET(block, pageCounter, recordCounter),
		      (uint8_t*) &recordMeta,
		      sizeof(record_meta_t));
      if(recordMeta.status == RECORD_EMPTY) {
	nextFreeRecord[block] = recordCounter;
	lastBlock[block] = pageCounter;
	break;
      }
    }
    // Didn't find a free record in the START block, search the first FREE block
    if(recordCounter == L_MAX_RECORDS_PER_BLOCK) {
      for(pageCounter = 0; pageCounter < L_PARTITIONS(block); pageCounter++) {
	call Flash.read(L_RAW_OFFSET(block, pageCounter, 0),
			(uint8_t*)&pageMeta,
			sizeof(page_meta_t));
	if(pageMeta.header == PAGE_AVAILABLE) {
	  for(recordCounter = 1; recordCounter < L_MAX_RECORDS_PER_BLOCK; recordCounter++) {
	    call Flash.read(L_RAW_OFFSET(block, pageCounter, recordCounter),
			    (uint8_t*) &recordMeta,
			    sizeof(record_meta_t));
	    if(recordMeta.status == RECORD_EMPTY) {
	      lastBlock[block] = pageCounter;
	      nextFreeRecord[block] = recordCounter;
	      goto mount_complete;
	    }
	  }
	}
      }
      // if here, you didn't find the last block, it must be right before the START block
      // special case the wrap around
      if(firstBlock[block] == 0)
	lastBlock[block] = L_PARTITIONS(block) - 1;
      else
	lastBlock[block] = firstBlock[block] - 1;
      // that last block must be full, so shuffle it
      shuffleBlocks(block);
    }

  mount_complete:
    readCookieOffset[block] = SEEK_BEGINNING;
    mountBits[block] = 1;
  }

  task void signalDoneTask() {
    switch(m_state) {
    case S_APPEND:
      m_state = S_IDLE;
      signal Write.appendDone[clientId](clientBuf, clientLen, clientResult);
      break;
    case S_SYNC:
      m_state = S_IDLE;
      signal Write.syncDone[clientId](SUCCESS);
      break;
    case S_ERASE:
      m_state = S_IDLE;
      signal Write.eraseDone[clientId](clientResult);
      break;
   case S_READ:
      m_state = S_IDLE;
      signal Read.readDone[clientId](clientBuf, clientLen, clientResult);
      break;
   case S_SEEK:
      m_state = S_IDLE;
      signal Read.seekDone[clientId](SUCCESS);
      break;
    default:
      break;
    }
  }

  /*
   * Invariant should be that everytime after an append completes,
   * nextFreeRecord should point to a valid free record slot. Uses
   * nextFreeRecord to append.
   */
  command error_t Write.append[ storage_volume_t block ](void* buf, storage_len_t len) {
    record_meta_t recordMeta;

    myMount(block);
    
    // error check
    if(len > L_RECORD_DATA_SIZE)
      return EINVAL;

    // if non circular log, fail
    if((!call Circular.get[block]()) &&
       (lastBlock[block] == (L_PARTITIONS(block) - 1)) &&
       (nextFreeRecord[block] == (L_MAX_RECORDS_PER_BLOCK - 1)))
      return FAIL;

    m_state = S_APPEND;
    clientId = block;
    clientBuf = buf;
    clientLen = len;

    // if you try to log 0, just immediately succeed, this really shouldn't happen
    if(len == 0) {
      clientResult = SUCCESS;
      post signalDoneTask();
      return SUCCESS;
    }

    // if readCookie was on SEEK_EOL, adjust it back to here
    if(readCookieOffset[block] == SEEK_EOL)
      readCookieOffset[block] = L_RAW_OFFSET(block, lastBlock[block], nextFreeRecord[block]) + sizeof(record_meta_t);
      
    // use next free record, write the INVALID, write the data, write the VALID
    recordMeta.status = RECORD_INVALID;
    recordMeta.length = len;
    call Flash.write(L_RAW_OFFSET(block, lastBlock[block], nextFreeRecord[block]),
		     (uint8_t*) &recordMeta,
		     sizeof(record_meta_t));
    call Flash.write(L_RAW_OFFSET(block, lastBlock[block], nextFreeRecord[block]) +
		     sizeof(record_meta_t),
		     (uint8_t*) buf, len);
    recordMeta.status = RECORD_VALID;
    call Flash.write(L_RAW_OFFSET(block, lastBlock[block], nextFreeRecord[block]),
		     (uint8_t*) &recordMeta,
		     sizeof(record_meta_t));
    nextFreeRecord[block]++;
    // see if you need to adjust blocks or shuffle
    if(nextFreeRecord[block] == L_MAX_RECORDS_PER_BLOCK)
      shuffleBlocks(block);

    clientResult = SUCCESS;
    post signalDoneTask();
    
    return SUCCESS;
  }

  /*
   * We use nextFreeRecord to get the cookie
   */
  command storage_cookie_t Write.currentOffset[ storage_volume_t block ]() {
    myMount(block);

    return L_RAW_OFFSET(block, lastBlock[block], nextFreeRecord[block]) +
      sizeof(record_meta_t);
  }

  /*
   * First we erase all the log data blocks so that they can be
   * reused. Then we zero the cookies and then write them to our
   * partitions like the append operation. If we crash in the middle,
   * you may have to erase again. However, if an erase does fail, at
   * least all your data will still be there, so that you can try
   * again.
   */
  command error_t Write.erase[storage_volume_t block]() {
    uint32_t i;

    for(i = 0; i < L_PARTITIONS(block); i++) {
      call Flash.erase(L_BASE_BLOCK(block) + (i * P30_BLOCK_SIZE));
    }

    mountBits[block] = 0;
    myMount(block);

    // ... starting block implicitly written by mount

    m_state = S_ERASE;
    clientId = block;
    clientResult = SUCCESS;
    post signalDoneTask();

    return SUCCESS;
  }

  /*
   * Sync does nothing really because unlike the AT45DB, Intel P30
   * writes directly through.
   */
  command error_t Write.sync[storage_volume_t block]() {
    myMount(block);

    m_state = S_SYNC;
    
    clientId = block;
    clientResult = SUCCESS;
    
    post signalDoneTask();
    return SUCCESS;

  }

  /*
   * Sanity check the read cookie and adjust for any other special
   * cookies. Because you can seek to the byte, must it is saved in
   * flash as records, you have to do a lot of tricky seeking, but
   * it's done here. Also has to handle any pages that are spilled
   * over.
   */
  command error_t Read.read[ storage_volume_t block ](void* buf, storage_len_t len) {
    record_meta_t recordMeta;
    uint32_t recordCounter;
    uint32_t pageCounter;
    uint32_t offset;

    clientId = block;
    clientBuf = buf;
    clientResult = SUCCESS;

    myMount(block);

    m_state = S_READ;
    
    if(len == 0 || readCookieOffset[block] == SEEK_EOL) {
      clientResult = SUCCESS;
      clientLen = 0;
      post signalDoneTask();
      return SUCCESS;
    }
    
    // adjust SEEK_BEGINNING to a real offset
    if(readCookieOffset[block] == SEEK_BEGINNING) {
      readCookieOffset[block] = L_RAW_OFFSET(block, firstBlock[block], 1) +
	sizeof(record_meta_t);
    }
    
    // convert the cookie to something useful
    cookieToTuple(readCookieOffset[block], block, &pageCounter, &recordCounter, &offset);
    // sanity check readCookie
    call Flash.read(L_RAW_OFFSET(block, pageCounter, recordCounter),
		    (uint8_t*) &recordMeta,
		    sizeof(record_meta_t));
    if((recordMeta.status == RECORD_VALID) && (offset > len)) {
      readCookieOffset[block] = L_RAW_OFFSET(block, firstBlock[block], 0) + sizeof(record_meta_t);
      cookieToTuple(readCookieOffset[block], block, &pageCounter, &recordCounter, &offset);
    }

    clientLen = 0; // reset how much actually read and count up

    
    while(len != 0) {
      call Flash.read(L_RAW_OFFSET(block, pageCounter, recordCounter),
		      (uint8_t*) &recordMeta,
		      sizeof(record_meta_t));
      if(recordMeta.status == RECORD_INVALID) {
	goto advance_counter;
      }
      if(recordMeta.status == RECORD_EMPTY) {
	readCookieOffset[block] = SEEK_EOL;
	post signalDoneTask();
	return SUCCESS;
      }
      // read partial block and finish
      if(len < recordMeta.length + offset) {
	call Flash.read(L_RAW_OFFSET(block, pageCounter, recordCounter) +
			offset + sizeof(record_meta_t),
			buf,
			len);
	offset = len;
	buf = buf + len;
	len = 0;
      }
      else {
	call Flash.read(L_RAW_OFFSET(block, pageCounter, recordCounter) + 
			offset + sizeof(record_meta_t),
			buf,
			recordMeta.length - offset);
	clientLen = clientLen + recordMeta.length - offset;
	len -= recordMeta.length - offset;
	buf = buf + recordMeta.length - offset;
	offset = 0;
      
      advance_counter:
	recordCounter++;
	if((recordCounter >= L_MAX_RECORDS_PER_BLOCK) && (pageCounter == lastBlock[block])) {
	  readCookieOffset[block] = SEEK_EOL;
	  post signalDoneTask();
	  return SUCCESS;
	}
	// need to adjust page possibly if spills
	// also need to check if reached end of log (lastBlock[block] or RECORD_AVAILABLE)
	if(recordCounter >= L_MAX_RECORDS_PER_BLOCK) {
	  pageCounter = (pageCounter + 1) % L_PARTITIONS(block);
	  recordCounter = 1;
	}
      }
    }

    readCookieOffset[block] = L_RAW_OFFSET(block, pageCounter, recordCounter) +
      sizeof(record_meta_t) + offset;
    post signalDoneTask();
    return SUCCESS;
  }
    
  command storage_cookie_t Read.currentOffset[ storage_volume_t block ]() {
    myMount(block);
    return readCookieOffset[block];
  }

  /*
   * Just set the cookie. If you seek into an invalid area, just set
   * it at SEEK_BEGINNING.
   */
  command error_t Read.seek[ storage_volume_t block ](storage_cookie_t offset) {
    uint32_t page;
    uint32_t record;
    uint32_t recordOffset;
    record_meta_t recordMeta;
    myMount(block);

    clientId = block;
    clientResult = SUCCESS;

    m_state = S_SEEK;

    readCookieOffset[block] = offset;

    post signalDoneTask();      
    
    return SUCCESS;
  }

  /*
   * Go through all the pages, if it's a free page, count whatever is
   * available left. Add them all up.
   */
  command storage_len_t Read.getSize[ storage_volume_t block ]() {
    storage_len_t len = 0;
    uint32_t i;
    uint32_t j;
    page_meta_t pageMeta;
    record_meta_t recordMeta;
    
    myMount(block);
    
    for(i = 0; i < L_PARTITIONS(block); i++) {
      call Flash.read(L_RAW_OFFSET(block, i, j),
		      (uint8_t*) &pageMeta,
		      sizeof(page_meta_t));
      if(pageMeta.header != PAGE_AVAILABLE) {
	len = len + (sizeof(record_data_t) * L_MAX_RECORDS_PER_BLOCK);
	continue;
      }
      for(j = 1; j < L_MAX_RECORDS_PER_BLOCK; j++) {
	call Flash.read(L_RAW_OFFSET(block, i, j),
			(uint8_t*) &recordMeta,
			sizeof(record_meta_t));
	if(recordMeta.status == RECORD_EMPTY) {
	  len = len + ((L_MAX_RECORDS_PER_BLOCK - j) * sizeof(record_meta_t));
	  break;
	}
      }
    }
    
    return len;
  }

  default event void Read.readDone[ storage_volume_t block ](void* buf, storage_len_t len, error_t error) {}
  default event void Read.seekDone[ storage_volume_t block ](error_t error) {}
  default event void Write.appendDone[ storage_volume_t block ](void* buf, storage_len_t len, error_t error) {}

  default event void Write.eraseDone[ storage_volume_t block ](error_t error) {}
  default event void Write.syncDone[ storage_volume_t block ](error_t error) {}

  default command bool Circular.get[ uint8_t id ]() { return FALSE; }
}

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

#ifndef __STORAGE_CHIP_H__
#define __STORAGE_CHIP_H__

typedef uint8_t storage_volume_t;
typedef uint8_t storage_block_t;
typedef uint8_t storage_log_t;
typedef uint8_t storage_config_t;

#endif



More information about the Tinyos-2-commits mailing list