[Tinyos-beta-commits] CVS: tinyos-1.x/beta/Deluge/Deluge BitVecUtils.h, NONE, 1.1 BitVecUtils.nc, NONE, 1.1 BitVecUtilsC.nc, NONE, 1.1 Deluge.h, NONE, 1.1 DelugeC.nc, NONE, 1.1 DelugeDataRead.nc, NONE, 1.1 DelugeDataWrite.nc, NONE, 1.1 DelugeImgDescStorage.nc, NONE, 1.1 DelugeM.nc, NONE, 1.1 DelugeMetadata.h, NONE, 1.1 DelugeMetadata.nc, NONE, 1.1 DelugeMetadataC.nc, NONE, 1.1 DelugeMetadataM.nc, NONE, 1.1 DelugeMetadataRead.nc, NONE, 1.1 DelugeMetadataWrite.nc, NONE, 1.1 DelugeMsgs.h, NONE, 1.1 DelugePageTransfer.h, NONE, 1.1 DelugePageTransfer.nc, NONE, 1.1 DelugePageTransferC.nc, NONE, 1.1 DelugePageTransferM.nc, NONE, 1.1 DelugeStorage.nc, NONE, 1.1 DelugeStorageC.nc, NONE, 1.1 DelugeStorageM.nc, NONE, 1.1 NetProg.h, NONE, 1.1 NetProg.nc, NONE, 1.1 NetProgC.nc, NONE, 1.1 NetProgM.nc, NONE, 1.1 SharedMsgBuf.nc, NONE, 1.1 SharedMsgBufM.nc, NONE, 1.1

Jonathan Hui jwhui at users.sourceforge.net
Sun Nov 21 21:31:00 PST 2004


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

Added Files:
	BitVecUtils.h BitVecUtils.nc BitVecUtilsC.nc Deluge.h 
	DelugeC.nc DelugeDataRead.nc DelugeDataWrite.nc 
	DelugeImgDescStorage.nc DelugeM.nc DelugeMetadata.h 
	DelugeMetadata.nc DelugeMetadataC.nc DelugeMetadataM.nc 
	DelugeMetadataRead.nc DelugeMetadataWrite.nc DelugeMsgs.h 
	DelugePageTransfer.h DelugePageTransfer.nc 
	DelugePageTransferC.nc DelugePageTransferM.nc DelugeStorage.nc 
	DelugeStorageC.nc DelugeStorageM.nc NetProg.h NetProg.nc 
	NetProgC.nc NetProgM.nc SharedMsgBuf.nc SharedMsgBufM.nc 
Log Message:
- Initial checkin of Deluge v2.0.

- New features:
  - Support for hardware write protect of external flash chip.
  - Ping results include information obtained from Ident.h.
  - CRCs are no longer inlined with program data, thus allowing for
    DMA transfers from external flash to program flash.
  - Version number information included in Deluge packets to prevent
    nodes with different versions of Deluge from conflicts.
  - Support for TinyOS 2.x hardware independent storage abstraction.
  - Metadata data-structures include CRCs generated by the host PC
    to help guard against corruption.
  - TOSBoot bootloader now written in nesC.
  - Reduced RAM and ROM requirements.
  - Other minor enhancements that I can't think of right now.

- Major user differences:
  - Golden image is now slot 0. While it cannot be written to, the user
    can retrieve Ident.h information about the golden image.
  - When specifying an image for download, the user specifies the 
    build/<platform> directory rather than just the ihex file. The issue
    is that it is very difficult to pull out the Ident.h information
    without compile-time output.

- Known issues:
  - Does not support more than 1 downloadable image (actually, it might, 
    but I haven't tested it yet).

- To setup the Deluge tools, create the directory net/tinyos/deluge
and copy all files in 'delugetools' into it.

- Operation is very similar to Deluge v1.0.
  Ping:
    $ java net.tinyos.deluge.Deluge -p
  Download:
    $ java net.tinyos.deluge.Deluge -i -if <builddir> -in <imagenum>
  Reboot:
    $ java net.tinyos.deluge.Deluge -r -in <imagenum>



--- NEW FILE: BitVecUtils.h ---
// $Id: BitVecUtils.h,v 1.1 2004/11/22 05:30:57 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."
 *
 */

/**
 * Provides generic methods for manipulating bit vectors.
 *
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

#ifndef __BITVEC_UTILS_H__
#define __BITVEC_UTILS_H__

#define BIT_GET(x, i) ((x) & (1 << (i)))
#define BIT_SET(x, i) ((x) | (1 << (i)))
#define BIT_CLEAR(x, i) ((x) & ~(1 << (i)))

#define BITVEC_GET(x, i) (BIT_GET((x)[(i)/8], (i)%8))
#define BITVEC_SET(x, i) ((x)[(i)/8] = BIT_SET((x)[(i)/8], (i)%8))
#define BITVEC_CLEAR(x, i) ((x)[(i)/8] = BIT_CLEAR((x)[(i)/8], (i)%8))

#endif

--- NEW FILE: BitVecUtils.nc ---
// $Id: BitVecUtils.nc,v 1.1 2004/11/22 05:30:57 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."
 *
 */

/**
 * Provides generic methods for manipulating bit vectors.
 *
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

interface BitVecUtils {
  /**
   * Locates the index of the first '1' bit in a bit vector.
   *
   * @param result     the location of the '1' bit
   * @param fromIndex  the index to start search for '1' bit
   * @param bitVec     the bit vector
   * @param length     the length of the bit vector in bits
   * @return           <code>SUCCESS</code> if a '1' bit was found;
   *                   <code>FAIL</code> otherwise.
   */
  command result_t indexOf(uint16_t* pResult, uint16_t fromIndex, 
			   uint8_t* bitVec, uint16_t length);

  /**
   * Counts the number of '1' bits in a bit vector.
   *
   * @param result  the number of '1' bits
   * @param bitVec  the bit vector
   * @param length  the length of the bit vector in bits
   * @return        <code>SUCCESS</code> if the operation completed successfully;
   *                <code>FAIL</code> otherwise.
   */
  command result_t countOnes(uint16_t* pResult, uint8_t* bitVec, 
			     uint16_t length);

  /**
   * Generates an ASCII representation of the bit vector.
   *
   * @param buf     the character array to place the ASCII string
   * @param bitVec  the bit vector
   * @param length  the length of the bit vector in bits
   */
  command void printBitVec(char* buf, uint8_t* bitVec, uint16_t length);
}

--- NEW FILE: BitVecUtilsC.nc ---
// $Id: BitVecUtilsC.nc,v 1.1 2004/11/22 05:30:57 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."
 *
 */

/**
 * Provides generic methods for manipulating bit vectors.
 *
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

includes BitVecUtils;

module BitVecUtilsC {
  provides interface BitVecUtils;
}

implementation {

  command result_t BitVecUtils.indexOf(uint16_t* pResult, uint16_t fromIndex, 
				       uint8_t* bitVec, uint16_t length) {
    
    uint16_t i = fromIndex;

    if (length == 0)
      return FAIL;
    
    do {
      if (BITVEC_GET(bitVec, i)) {
	*pResult = i;
	return SUCCESS;
      }
      i = (i+1) % length;
    } while (i != fromIndex);
    
    return FAIL;
    
  }

  command result_t BitVecUtils.countOnes(uint16_t* pResult, uint8_t* bitVec, uint16_t length) {

    int count = 0;
    int i;

    for ( i = 0; i < length; i++ ) {
      if (BITVEC_GET(bitVec, i))
	count++;
    }

    *pResult = count;

    return SUCCESS;

  }

  command void BitVecUtils.printBitVec(char* buf, uint8_t* bitVec, uint16_t length) {
#ifdef PLATFORM_PC
    uint16_t i;
    
    dbg(DBG_TEMP, "");
    for ( i = 0; i < length; i++ ) {
      sprintf(buf++, "%d", !!BITVEC_GET(bitVec, i));
    }
#endif	  
  }

}

--- NEW FILE: Deluge.h ---

#ifndef __DELUGE_H__
#define __DELUGE_H__

#include "DelugeMetadata.h"

enum {
  DELUGE_VERSION                    = 2,
  DELUGE_NUM_IMAGES                 = 2,
  DELUGE_MIN_ADV_PERIOD_LOG2        = 9,
  DELUGE_MAX_ADV_PERIOD_LOG2        = 20,
  DELUGE_NUM_NEWDATA_ADVS_REQUIRED  = 2,
  DELUGE_NUM_MIN_ADV_PERIODS        = 2,
  DELUGE_MAX_NUM_REQ_TRIES          = 1,
  DELUGE_REBOOT_DELAY               = 4,
  DELUGE_FAILED_SEND_DELAY          = 16,
  DELUGE_MIN_DELAY                  = 16,
  DELUGE_MAX_REQ_DELAY              = (0x1 << (DELUGE_MIN_ADV_PERIOD_LOG2-1)),
  DELUGE_NACK_TIMEOUT               = (DELUGE_MAX_REQ_DELAY >> 0x1),
  DELUGE_MAX_IMAGE_SIZE             = ((uint32_t)128*(uint32_t)1024),
  DELUGE_PAGE_SIZE                  = 1024,
  DELUGE_MAX_PAGES                  = DELUGE_MAX_IMAGE_SIZE/DELUGE_PAGE_SIZE,
  DELUGE_CRC_SIZE                   = 2,
  DELUGE_CRC_BLOCK_SIZE             = DELUGE_MAX_PAGES*DELUGE_CRC_SIZE,
  DELUGE_FACTORY_IMAGE_NUM          = 0x0,
  DELUGE_INVALID_VNUM               = -1,
  DELUGE_INVALID_IMGNUM             = 0xff,
  DELUGE_INVALID_PKTNUM             = 0xff,
  DELUGE_INVALID_PGNUM              = 0xff,
  DELUGE_IMAGE0_VOLUME              = unique("FlashVolume"),
  DELUGE_IMAGE1_VOLUME              = unique("FlashVolume"),
  DELUGE_DATA_OFFSET                = 128,
  DELUGE_IDENT_SIZE                 = 128,
  DELUGE_INVALID_ADDR               = ((uint32_t)0x7fffffff),
};

typedef struct DelugeAdvTimer {
  uint32_t timer      : 24;
  uint32_t periodLog2 : 7;
  uint32_t overheard  : 1;
  uint8_t  newAdvs;
} DelugeAdvTimer;

typedef struct DelugeNodeDesc {
  imgvnum_t vNum;
  imgnum_t  imgNum;
  uint8_t   dummy;
  uint16_t  crc;
} DelugeNodeDesc;

#define IFLASH_GVNUM_ADDR 0x56

#endif

--- NEW FILE: DelugeC.nc ---

includes BitVecUtils;
includes Deluge;
includes DelugeMetadata;
includes DelugePageTransfer;
includes DelugeMsgs;

configuration DelugeC {
  provides {
    interface StdControl;
  }
}

implementation {

  components
    Main,
    BitVecUtilsC,
    DelugeM,
    DelugeMetadataC as Metadata,
    DelugePageTransferC as PageTransfer,
    GenericComm as Comm,
    LedsC as Leds,
    NetProgC,
    RandomLFSR,
    SharedMsgBufM,
    TimerC;

#ifndef PLATFORM_PC
  components InternalFlashC as IFlash;
  DelugeM.IFlash -> IFlash;
#endif

  StdControl = DelugeM;

  DelugeM.MetadataControl -> Metadata;
  DelugeM.SubStdControl -> Comm;
  DelugeM.SubStdControl -> NetProgC;
  DelugeM.SubStdControl -> PageTransfer;
  DelugeM.SubStdControl -> SharedMsgBufM;
  DelugeM.SubStdControl -> TimerC;

  DelugeM.Leds -> Leds;
  DelugeM.Metadata -> Metadata.Metadata[unique("DelugeMetadata")];
  DelugeM.NetProg -> NetProgC;
  DelugeM.PageTransfer -> PageTransfer;
  DelugeM.Random -> RandomLFSR;
  DelugeM.ReceiveAdvMsg -> Comm.ReceiveMsg[AM_DELUGEADVMSG];
  DelugeM.SendAdvMsg-> Comm.SendMsg[AM_DELUGEADVMSG];
  DelugeM.SharedMsgBuf -> SharedMsgBufM.SharedMsgBuf[DELUGE_SHARED_MSG_BUF];
  DelugeM.Timer -> TimerC.Timer[unique("Timer")];

  PageTransfer.Leds -> Leds;
  PageTransfer.ReceiveDataMsg -> Comm.ReceiveMsg[AM_DELUGEDATAMSG];
  PageTransfer.ReceiveReqMsg -> Comm.ReceiveMsg[AM_DELUGEREQMSG];
  PageTransfer.SendDataMsg -> Comm.SendMsg[AM_DELUGEDATAMSG];
  PageTransfer.SendReqMsg -> Comm.SendMsg[AM_DELUGEREQMSG];
  PageTransfer.SharedMsgBuf -> SharedMsgBufM.SharedMsgBuf[DELUGE_SHARED_MSG_BUF];

}

--- NEW FILE: DelugeDataRead.nc ---

includes BlockStorage;
includes Deluge;

interface DelugeDataRead {

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

}

--- NEW FILE: DelugeDataWrite.nc ---

interface DelugeDataWrite {

  command result_t write(imgnum_t imgNum, block_addr_t addr, 
			 uint8_t* source, block_addr_t len);
  event   result_t writeDone(result_t result);

  command result_t erase(imgnum_t imgNum);
  event   result_t eraseDone(result_t result);

}

--- NEW FILE: DelugeImgDescStorage.nc ---

interface DelugeImgDescStorage {

}
--- NEW FILE: DelugeM.nc ---

module DelugeM {
  provides {
    interface StdControl;
  }
  uses {
    interface DelugeMetadata as Metadata;
    interface DelugePageTransfer as PageTransfer;
    interface Leds;
    interface InternalFlash as IFlash;
    interface NetProg;
    interface Random;
    interface ReceiveMsg as ReceiveAdvMsg;
    interface SendMsg as SendAdvMsg;
    interface SharedMsgBuf;
    interface SplitControl as MetadataControl;
    interface StdControl as SubStdControl;
    interface Timer;
  }
}

implementation {

  enum {
    DELUGE_NUM_TIMERS = DELUGE_NUM_IMAGES-1,
  };

  DelugeAdvTimer advTimers[DELUGE_NUM_TIMERS];
  DelugeNodeDesc nodeDesc;
  
  uint8_t rebootDelay;

  void setupAdvTimer(DelugeAdvTimer* timer) {
    timer->timer = 0x1 << (timer->periodLog2-1);
    timer->timer += call Random.rand() & (timer->timer-1);
  }
  
  uint8_t findMinTimer() {

    uint32_t minDelay = advTimers[0].timer;
    uint8_t  minTimer = 0;
    uint8_t  i;

    for ( i = 1; i < DELUGE_NUM_TIMERS; i++ ) {
      if (advTimers[i].timer < minDelay)
	minTimer = i;
    }

    return minTimer;

  }

  void startTimer() {
    
    uint8_t minTimer = findMinTimer();

    if (advTimers[minTimer].timer < 2)
      advTimers[minTimer].timer += 2;
    
    call Timer.stop();
    call Timer.start(TIMER_ONE_SHOT, advTimers[minTimer].timer);

  }

  command result_t StdControl.init() {
    result_t result;
    call IFlash.read((uint16_t*)IFLASH_GVNUM_ADDR, &nodeDesc.vNum, sizeof(nodeDesc.vNum));
    result = call Leds.init();
    result = rcombine(call SubStdControl.init(), result);
    result = rcombine(call MetadataControl.init(), result);
    return result;
  }

  command result_t StdControl.start() {
    result_t result;
    nodeDesc.imgNum = call NetProg.getExecutingImgNum();
    result = call SubStdControl.start();
    result = rcombine(call MetadataControl.start(), result);
    return result;
  }

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

  event result_t MetadataControl.initDone() {
    return SUCCESS;
  }

  event result_t MetadataControl.startDone() { 

    uint8_t i;

    for ( i = 0; i < DELUGE_NUM_TIMERS; i++ ) {
      advTimers[i].periodLog2 = DELUGE_MIN_ADV_PERIOD_LOG2;
      setupAdvTimer(&advTimers[i]);
    }
    rebootDelay = 0;

    startTimer();

    return SUCCESS; 

  }

  event result_t MetadataControl.stopDone() { 
    return SUCCESS; 
  }

  void fillAdvMsg(imgnum_t image, DelugeAdvMsg* pMsg) {
    pMsg->sourceAddr = TOS_LOCAL_ADDRESS;
    pMsg->version = DELUGE_VERSION;
    pMsg->type = DELUGE_ADV_NORMAL;
    pMsg->nodeDesc = nodeDesc;
    call Metadata.getImgDesc(image, &(pMsg->imgDesc));
  }

  event result_t Timer.fired() {

    uint8_t minTimer = findMinTimer();
    uint8_t i;

    if (call PageTransfer.getWorkingImage() == DELUGE_INVALID_IMGNUM)
      call Leds.redOn();
    else
      call Leds.redOff();

    if (rebootDelay == 0)
      call Leds.yellowOff();

    call Leds.greenToggle();

    for ( i = 0; i < DELUGE_NUM_TIMERS; i++ )
      advTimers[i].timer -= advTimers[minTimer].timer;

    if (!advTimers[minTimer].overheard
	&& !call SharedMsgBuf.isLocked()
	&& !call PageTransfer.isTransferring()) {
      TOS_MsgPtr pMsgBuf = call SharedMsgBuf.getMsgBuf();
      fillAdvMsg(minTimer+1, (DelugeAdvMsg*)(pMsgBuf->data));
      if (call SendAdvMsg.send(TOS_BCAST_ADDR, sizeof(DelugeAdvMsg), pMsgBuf) == SUCCESS)
	call SharedMsgBuf.lock();
    }

    if (advTimers[minTimer].newAdvs > 0)
      advTimers[minTimer].newAdvs--;

    if (rebootDelay > 0) {
      if (rebootDelay == 1) {
	call IFlash.write((uint16_t*)IFLASH_GVNUM_ADDR, &nodeDesc.vNum, sizeof(nodeDesc.vNum));
	call NetProg.programImgAndReboot(nodeDesc.imgNum); // SHOULD NOT RETURN!
	// XXX: WHAT DO WE DO HERE?
      }
      rebootDelay--;
    }
    else if (advTimers[minTimer].newAdvs == 0
	     && rebootDelay == 0
	     && advTimers[minTimer].periodLog2 < DELUGE_MAX_ADV_PERIOD_LOG2) {
      advTimers[minTimer].periodLog2++;
    }

    advTimers[minTimer].overheard = 0;
    
    setupAdvTimer(&advTimers[minTimer]);
    
    startTimer();

    return SUCCESS;
    
  }

  event TOS_MsgPtr ReceiveAdvMsg.receive(TOS_MsgPtr pMsg) {
    
    DelugeAdvMsg *rxAdvMsg = (DelugeAdvMsg*)(pMsg->data);
    imgnum_t imgNum = rxAdvMsg->imgDesc.imgNum;
    dm_cmp_t cmpResult = call Metadata.compareImgDesc(&(rxAdvMsg->imgDesc));

    if (rxAdvMsg->version != DELUGE_VERSION)
      return pMsg;

    if (rxAdvMsg->type == DELUGE_ADV_PC) {
      // adv message from PC
      if ((rxAdvMsg->nodeDesc.vNum == DELUGE_INVALID_VNUM
	   && rxAdvMsg->nodeDesc.imgNum == DELUGE_INVALID_IMGNUM)
	  || (cmpResult == DELUGE_IMGDESC_EQUAL)) {
	if (!call SharedMsgBuf.isLocked()) {
	  TOS_MsgPtr pMsgBuf = call SharedMsgBuf.getMsgBuf();
	  fillAdvMsg(imgNum, (DelugeAdvMsg*)pMsgBuf->data);
	  if (call SendAdvMsg.send(rxAdvMsg->sourceAddr, sizeof(DelugeAdvMsg), pMsgBuf) == SUCCESS)
	    call SharedMsgBuf.lock();
	}
	return pMsg;
      }
    }

    // don't listen to advertisements about the factory image
    if (imgNum == DELUGE_FACTORY_IMAGE_NUM)
      return pMsg;

    switch (cmpResult) {
    case DELUGE_IMGDESC_EQUAL:
      advTimers[imgNum-1].overheard = 1;
      break;
    case DELUGE_IMGDESC_NEWER:
      call Metadata.setupNewImage(&(rxAdvMsg->imgDesc));
      break;
    case DELUGE_IMGDESC_LARGER:
      // notify page transfer of more data
      if (advTimers[imgNum-1].newAdvs == 0)
	call PageTransfer.dataAvailable(rxAdvMsg->sourceAddr);
      break;
    }

    if (cmpResult != DELUGE_IMGDESC_EQUAL) {
      advTimers[imgNum-1].periodLog2 = DELUGE_MIN_ADV_PERIOD_LOG2;
      setupAdvTimer(&advTimers[imgNum-1]);
      startTimer();
    }

    if ((rxAdvMsg->nodeDesc.vNum - nodeDesc.vNum) > 0
	&& rxAdvMsg->nodeDesc.vNum != DELUGE_INVALID_VNUM
	&& call Metadata.isComplete(imgNum)) {
      call Leds.yellowOn();
      nodeDesc = rxAdvMsg->nodeDesc;
      advTimers[imgNum-1].periodLog2 = DELUGE_MIN_ADV_PERIOD_LOG2;
      rebootDelay = DELUGE_REBOOT_DELAY;
      setupAdvTimer(&advTimers[imgNum-1]);
      startTimer();
    }

    return pMsg;

  }

  void setNextPage() {

    DelugeImgDesc imgDesc;
    uint8_t i;

    for ( i = 0; i < DELUGE_NUM_IMAGES; i++ ) {
      call Metadata.getImgDesc(i, &imgDesc);
      if (imgDesc.numPgs != imgDesc.numPgsComplete)
	break;
    }

    if (i < DELUGE_NUM_IMAGES)
      call PageTransfer.setWorkingPage(i, imgDesc.numPgsComplete);

  }

  event result_t Metadata.setupNewImageDone(result_t result) {
    setNextPage();
    return SUCCESS;
  }

  event result_t SendAdvMsg.sendDone(TOS_MsgPtr pMsg, result_t result) {
    dbg(DBG_USR1, "send adv message\n");
    call SharedMsgBuf.unlock();
    return SUCCESS;
  }

  event result_t PageTransfer.receivedPage(imgnum_t imgNum, pgnum_t pgNum) {
    call Metadata.receivedPage(imgNum, pgNum);
    advTimers[imgNum-1].newAdvs = DELUGE_NUM_NEWDATA_ADVS_REQUIRED;    
    setNextPage();
    return SUCCESS;
  }

  event result_t SharedMsgBuf.bufFree() { return SUCCESS; }

}

--- NEW FILE: DelugeMetadata.h ---

#ifndef __DELUGE_METADATA_H__
#define __DELUGE_METADATA_H__

enum {
  DELUGE_IMGDESC_NEWER,   // newer object
  DELUGE_IMGDESC_OLDER,   // older object
  DELUGE_IMGDESC_LARGER,  // more pages of same object
  DELUGE_IMGDESC_SMALLER, // less pages of same object
  DELUGE_IMGDESC_EQUAL,   // identical
};

typedef int8_t   dm_cmp_t;
typedef int16_t  imgvnum_t;
typedef uint8_t  imgnum_t;
typedef uint8_t  pgnum_t;

typedef struct DelugeImgDesc {
  imgvnum_t vNum;           // version num of image
  imgnum_t  imgNum;         // image number
  pgnum_t   numPgs;         // num pages of complete image
  uint16_t  crc;            // crc for vNum and numPgs
  uint8_t   numPgsComplete; // numPgsComplete in image
  uint8_t   dummy;          // make data structure word aligned
} DelugeImgDesc;

#endif

--- NEW FILE: DelugeMetadata.nc ---

interface DelugeMetadata {

  command bool isComplete(imgnum_t imgNum);

  command result_t setupNewImage(DelugeImgDesc* imgDesc);
  event   result_t setupNewImageDone(result_t result);
  command result_t getImgDesc(imgnum_t imgNum, DelugeImgDesc* imgDesc);
  command dm_cmp_t compareImgDesc(DelugeImgDesc* imgDesc);

  command imgvnum_t getVNum(imgnum_t imgNum);
  command pgnum_t getNumPgsComplete(imgnum_t imgNum);

  command result_t receivedPage(imgnum_t imgNum, pgnum_t pgNum);

}

--- NEW FILE: DelugeMetadataC.nc ---

includes BlockStorage;

configuration DelugeMetadataC {
  provides {
    interface DelugeMetadata as Metadata[uint8_t id];
    interface SplitControl;
  }
}

implementation {

  components
    DelugeMetadataM,
    DelugeStorageC as Storage;

  SplitControl = DelugeMetadataM;
  Metadata = DelugeMetadataM;

  DelugeMetadataM.DataWrite -> Storage.DataWrite[unique("DelugeDataWrite")];
  DelugeMetadataM.MetadataRead -> Storage.MetadataRead[unique("DelugeMetadataRead")];
  DelugeMetadataM.MetadataWrite -> Storage.MetadataWrite[unique("DelugeMetadataWrite")];
  DelugeMetadataM.SubControl -> Storage;

}

--- NEW FILE: DelugeMetadataM.nc ---

module DelugeMetadataM {
  provides {
    interface SplitControl;
    interface DelugeMetadata as Metadata[uint8_t id];
  }
  uses {
    interface DelugeDataWrite as DataWrite;
    interface DelugeMetadataRead as MetadataRead;
    interface DelugeMetadataWrite as MetadataWrite;
    interface StdControl as SubControl;
  }
}

implementation {

  DelugeImgDesc imgDesc[DELUGE_NUM_IMAGES];

  uint8_t client;
  uint8_t curImage;
  uint8_t state;

  enum {
    S_INIT,
    S_IDLE,
    S_READ_IMG_DESC,
    S_WRITE_IMG_DESC,
    S_ERASE_IMG_DESC,
  };

  task void retry() {

    result_t result = SUCCESS;

    switch(state) {
    case S_ERASE_IMG_DESC:
      result = call DataWrite.erase(curImage);
      break;
    case S_READ_IMG_DESC:
      result = call MetadataRead.read(curImage, &(imgDesc[curImage]));
      break;
    case S_WRITE_IMG_DESC:
      result = call MetadataWrite.write(curImage, &(imgDesc[curImage]));
      break;
    }

    if (result == FAIL)
      post retry();

  }

  command result_t SplitControl.init() {

    result_t result;

    state = S_INIT;

    result = call SubControl.init();

#ifdef PLATFORM_PC
    if (TOS_LOCAL_ADDRESS == 0) {
      imgDesc[0].vNum = 1;
      imgDesc[0].imgNum = 0;
      imgDesc[0].numPgs = 5;
      imgDesc[0].numPgsComplete = 5;
    }
#endif

    return SUCCESS;

  }

  command result_t SplitControl.start() {

    result_t result;

    result = call SubControl.start();

    state = S_READ_IMG_DESC;
    curImage = 0;
    if (call MetadataRead.read(curImage, &(imgDesc[curImage])) == FAIL)
      post retry();

    return SUCCESS;

  }

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

  command bool Metadata.isComplete[uint8_t id](imgnum_t imgNum) {
    if (state == S_IDLE
	&& imgNum < DELUGE_NUM_IMAGES
	&& imgDesc[imgNum].numPgsComplete != 0
	&& (imgDesc[imgNum].numPgs == imgDesc[imgNum].numPgsComplete))
      return TRUE;
    return FALSE;
  }

  command imgvnum_t Metadata.getVNum[uint8_t id](imgnum_t imgNum) {
    return imgDesc[imgNum].vNum;
  }

  command pgnum_t Metadata.getNumPgsComplete[uint8_t id](imgnum_t imgNum) {
    return imgDesc[imgNum].numPgsComplete;
  }

  command result_t Metadata.receivedPage[uint8_t id](imgnum_t imgNum, pgnum_t pgNum) {

    if (imgNum >= DELUGE_NUM_IMAGES)
      return FAIL;

    // increment numPgsComplete
    if (imgDesc[imgNum].numPgsComplete < imgDesc[imgNum].numPgs
	&& imgDesc[imgNum].numPgsComplete == pgNum)
      imgDesc[imgNum].numPgsComplete++;

    // if image is complete, write out numPgsComplete
    if (imgDesc[imgNum].numPgsComplete == imgDesc[imgNum].numPgs) {
      state = S_WRITE_IMG_DESC;
      curImage = imgNum;
      if (call MetadataWrite.write(curImage, &(imgDesc[curImage])) == FAIL)
	post retry();
    }

    return SUCCESS;

  }

  command result_t Metadata.setupNewImage[uint8_t id](DelugeImgDesc* newImgDesc) {

    if (state != S_IDLE
	|| newImgDesc->imgNum >= DELUGE_NUM_IMAGES)
      return FALSE;

    client = id;

    memcpy(&(imgDesc[newImgDesc->imgNum]), newImgDesc, sizeof(DelugeImgDesc));
    imgDesc[newImgDesc->imgNum].numPgsComplete = 0;

    state = S_ERASE_IMG_DESC;
    curImage = newImgDesc->imgNum;
    if (call DataWrite.erase(curImage) == FAIL)
      post retry();

    return SUCCESS;

  }

  command result_t Metadata.getImgDesc[uint8_t id](uint8_t imgNum, DelugeImgDesc* newImgDesc) {

    if (imgNum >= DELUGE_NUM_IMAGES)
      return FAIL;

    memcpy(newImgDesc, &(imgDesc[imgNum]), sizeof(DelugeImgDesc));
    
    return SUCCESS;

  }

  command dm_cmp_t Metadata.compareImgDesc[uint8_t id](DelugeImgDesc* cmpImgDesc) {
    
    imgnum_t image = cmpImgDesc->imgNum;
    
    if (image >= DELUGE_NUM_IMAGES)
      return DELUGE_IMGDESC_EQUAL;

    if ((cmpImgDesc->vNum - imgDesc[image].vNum) > 0)
      return DELUGE_IMGDESC_NEWER;
    else if ((cmpImgDesc->vNum - imgDesc[image].vNum) < 0)
      return DELUGE_IMGDESC_OLDER;
    else if (cmpImgDesc->numPgsComplete > imgDesc[image].numPgsComplete)
      return DELUGE_IMGDESC_LARGER;
    else if (cmpImgDesc->numPgsComplete < imgDesc[image].numPgsComplete)
      return DELUGE_IMGDESC_SMALLER;

    return DELUGE_IMGDESC_EQUAL;

  }

  event result_t MetadataRead.readDone(result_t result) {

    if (imgDesc[curImage].vNum == DELUGE_INVALID_VNUM) {
      imgDesc[curImage].imgNum = curImage;
      imgDesc[curImage].numPgs = 0;
      imgDesc[curImage].crc = 0;
      imgDesc[curImage].numPgsComplete = 0;
    }

    if (state == S_READ_IMG_DESC) {
      curImage++;
      if (curImage < DELUGE_NUM_IMAGES) {
	if (call MetadataRead.read(curImage, &(imgDesc[curImage])) == FAIL)
	  post retry();
      }
    }

    state = S_IDLE;

    return signal SplitControl.startDone();

  }

  event result_t DataWrite.eraseDone(result_t result) {
    state = S_IDLE;
    return signal Metadata.setupNewImageDone[client](result);
  }
  
  event result_t MetadataWrite.writeDone(result_t result) {
    state = S_IDLE;
    return SUCCESS;
  }

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

  default event result_t Metadata.setupNewImageDone[uint8_t id](result_t result) {
    return SUCCESS; 
  }

}

--- NEW FILE: DelugeMetadataRead.nc ---

interface DelugeMetadataRead {

  command result_t read(imgnum_t imgNum, DelugeImgDesc* imgDesc);
  event result_t readDone(result_t result);

}

--- NEW FILE: DelugeMetadataWrite.nc ---

interface DelugeMetadataWrite {

  command result_t write(imgnum_t imgNum, DelugeImgDesc* imgDesc);
  event result_t writeDone(result_t result);

}

--- NEW FILE: DelugeMsgs.h ---

#ifndef __DELUGE_MSGS_H__
#define __DELUGE_MSGS_H__

#include "Deluge.h"
#include "DelugeMetadata.h"
#include "DelugePageTransfer.h"

enum {
  DELUGE_SHARED_MSG_BUF = unique("SharedMsgBuf"),
};

enum {
  AM_DELUGEADVMSG       = 161,
  AM_DELUGEREQMSG       = 162,
  AM_DELUGEDATAMSG      = 163,
  AM_DELUGEPINGREPLYMSG = 164,
};

enum {
  DELUGE_ADV_NORMAL    = 0,
  DELUGE_ADV_PC        = 1,
  DELUGE_ADV_PING      = 2,
  DELUGE_ADV_NOT_READY = 3,
};

typedef struct DelugeAdvMsg {
  uint16_t       sourceAddr; // 2
  uint8_t        version;    // 1
  uint8_t        type;       // 1
  DelugeNodeDesc nodeDesc;   // 6
  DelugeImgDesc  imgDesc;    // 8
} DelugeAdvMsg;

typedef struct DelugeReqMsg {
  uint16_t  dest;
  uint16_t  sourceAddr;
  imgvnum_t vNum;
  imgnum_t  imgNum;
  pgnum_t   pgNum;
  uint8_t   requestedPkts[DELUGE_PKT_BITVEC_SIZE];
} DelugeReqMsg;

typedef struct DelugeDataMsg {
  imgvnum_t vNum;
  imgnum_t  imgNum;
  pgnum_t   pgNum;
  uint8_t   pktNum;
  uint8_t   data[DELUGE_PKT_PAYLOAD_SIZE];
} DelugeDataMsg;

#endif

--- NEW FILE: DelugePageTransfer.h ---

#ifndef __DELUGE_PAGE_TRANSFER_H__
#define __DELUGE_PAGE_TRANSFER_H__

enum {
  DELUGE_PKTS_PER_PAGE    = 48,
  DELUGE_PKT_PAYLOAD_SIZE = 23,
  DELUGE_BYTES_PER_PAGE   = (DELUGE_PKTS_PER_PAGE*DELUGE_PKT_PAYLOAD_SIZE),
  DELUGE_PKT_BITVEC_SIZE  = (((DELUGE_PKTS_PER_PAGE-1) / 8) + 1),
  DELUGE_DATA_Q_SIZE      = 2,
};

#endif

--- NEW FILE: DelugePageTransfer.nc ---

interface DelugePageTransfer {
  command result_t setWorkingPage(imgnum_t imgNum, pgnum_t pgNum);
  command imgnum_t getWorkingImage();
  command pgnum_t  getWorkingPage();
  command bool     isTransferring();
  command result_t dataAvailable(uint16_t sourceAddr);
  event   result_t receivedPage(imgnum_t imgNum, pgnum_t pgNum);
}

--- NEW FILE: DelugePageTransferC.nc ---

configuration DelugePageTransferC {
  provides {
    interface StdControl;
    interface DelugePageTransfer;
  }
  uses {
    interface Leds;
    interface SendMsg as SendReqMsg;
    interface SendMsg as SendDataMsg;
    interface ReceiveMsg as ReceiveReqMsg;
    interface ReceiveMsg as ReceiveDataMsg;
    interface SharedMsgBuf;
  }
}

implementation {

  components
    DelugePageTransferM,
    BitVecUtilsC,
    DelugeMetadataC as Metadata,
    DelugeStorageC as Storage,
    RandomLFSR,
    TimerC;
  
  StdControl = DelugePageTransferM;
  
  DelugePageTransfer = DelugePageTransferM;
  Leds = DelugePageTransferM;
  
  DelugePageTransferM.SubControl -> Storage;
  DelugePageTransferM.SubControl -> TimerC;

  DelugePageTransferM.BitVecUtils -> BitVecUtilsC;
  DelugePageTransferM.DataRead -> Storage.DataRead[unique("DelugeDataRead")];
  DelugePageTransferM.DataWrite -> Storage.DataWrite[unique("DelugeDataWrite")];
  DelugePageTransferM.Metadata -> Metadata.Metadata[unique("DelugeMetadata")];
  DelugePageTransferM.Random -> RandomLFSR;
  DelugePageTransferM.ReceiveDataMsg = ReceiveDataMsg;
  DelugePageTransferM.ReceiveReqMsg = ReceiveReqMsg;
  DelugePageTransferM.ReqTimer -> TimerC.Timer[unique("Timer")];
  DelugePageTransferM.SendDataMsg = SendDataMsg;
  DelugePageTransferM.SendReqMsg = SendReqMsg;
  DelugePageTransferM.SharedMsgBuf = SharedMsgBuf;

}

--- NEW FILE: DelugePageTransferM.nc ---

module DelugePageTransferM {
  provides {
    interface StdControl;
    interface DelugePageTransfer as PageTransfer;
  }
  uses {
    interface BitVecUtils;
    interface DelugeMetadata as Metadata;
    interface DelugeDataRead as DataRead;
    interface DelugeDataWrite as DataWrite;
    interface Leds;
    interface Random;
    interface ReceiveMsg as ReceiveDataMsg;
    interface ReceiveMsg as ReceiveReqMsg;
    interface SendMsg as SendDataMsg;
    interface SendMsg as SendReqMsg;
    interface SharedMsgBuf;
    interface StdControl as SubControl;
    interface Timer as ReqTimer;
  }
}

implementation {

  typedef struct {
    uint16_t dataSourceAddr;
    uint8_t  numReqTriesLeft;
    bool     suppressReq;
  } RxState;

  typedef struct {
    uint16_t dest;
    uint8_t imgToSend;
    uint8_t pageToSend;
  } TxState;

  typedef struct {
    union {
      RxState rx; 
      TxState tx; 
    };
  } RxTxState;

  // send/receive page buffers, and state variables for buffers
  uint8_t  pktsToSend[DELUGE_PKT_BITVEC_SIZE];    // bit vec of packets to send
  uint8_t  pktsToReceive[DELUGE_PKT_BITVEC_SIZE]; // bit vec of packets to receive

  typedef struct {
    uint8_t pktNum;
    uint8_t data[DELUGE_PKT_PAYLOAD_SIZE];
  } ReceivedData;

  ReceivedData receivedData;

  // state variables
  uint8_t   state;
  RxTxState vars;

  imgnum_t  workingImgNum;
  pgnum_t   workingPgNum;

  enum {
    S_DISABLED,
    S_IDLE,     
    S_TX_LOCKING,
    S_SENDING,
    S_RX_LOCKING,
    S_RECEIVING,
  };

  void changeState(uint8_t newState) {
    
    switch(newState) {
    case S_DISABLED: case S_IDLE:
      if (state == S_SENDING || state == S_RECEIVING)
	call SharedMsgBuf.unlock();
      break;
    }

    state = newState;
    
  }

  command result_t StdControl.init() {
    changeState(S_DISABLED);
    receivedData.pktNum = DELUGE_INVALID_PKTNUM;
    workingImgNum = DELUGE_INVALID_IMGNUM;
    workingPgNum = DELUGE_INVALID_PGNUM;
    return call SubControl.init();
  }

  command result_t StdControl.start() {
    changeState(S_IDLE);
    return call SubControl.start();
  }

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

  command result_t PageTransfer.setWorkingPage(imgnum_t imgNum, pgnum_t pgNum) {
    workingImgNum = imgNum;
    workingPgNum = pgNum;
    memset(pktsToReceive, 0xff, DELUGE_PKT_BITVEC_SIZE);
    return SUCCESS;
  }

  command imgnum_t PageTransfer.getWorkingImage() {
    return workingImgNum;
  }

  command pgnum_t PageTransfer.getWorkingPage() {
    return workingPgNum;
  }

  command bool PageTransfer.isTransferring() {
    return (state != S_IDLE && state != S_DISABLED);
  }

  command result_t PageTransfer.dataAvailable(uint16_t sourceAddr) {

    if (workingImgNum == DELUGE_INVALID_IMGNUM)
      return FAIL;

    if (state == S_IDLE) {
      // currently idle, so request data from source
      changeState(S_RX_LOCKING);
      vars.rx.dataSourceAddr = sourceAddr;
      vars.rx.suppressReq = FALSE;
      
      // randomize request to prevent collision
      call ReqTimer.start(TIMER_ONE_SHOT, DELUGE_MIN_DELAY + 
			  call Random.rand() % DELUGE_MAX_REQ_DELAY);
    }
    
    return SUCCESS;

  }

  uint32_t calcOffset(pgnum_t pgNum, uint8_t pktNum) {
    return (uint32_t)pgNum*(uint32_t)DELUGE_BYTES_PER_PAGE
      + (uint32_t)pktNum*(uint32_t)DELUGE_PKT_PAYLOAD_SIZE;
  }
  
  void setupDataMsg();

  task void retrySetupDataMsg() {
    setupDataMsg();
  }

  void setupDataMsg() {
    TOS_MsgPtr pMsgBuf = call SharedMsgBuf.getMsgBuf();
    DelugeDataMsg* pDataMsg = (DelugeDataMsg*)(pMsgBuf->data);
    uint32_t offset;
    uint16_t nextPkt;

    if (state != S_SENDING && state != S_TX_LOCKING)
      return;

    if (state == S_TX_LOCKING) {
      if (call SharedMsgBuf.lock() == FAIL) {
	post retrySetupDataMsg();
	return;
      }
      changeState(S_SENDING);
      pDataMsg->vNum = call Metadata.getVNum(vars.tx.imgToSend);
      pDataMsg->imgNum = vars.tx.imgToSend;
      pDataMsg->pgNum = vars.tx.pageToSend;
      pDataMsg->pktNum = 0;
    }
    
    if (!call BitVecUtils.indexOf(&nextPkt, pDataMsg->pktNum, pktsToSend, 
				  DELUGE_PKTS_PER_PAGE)
	&& !call BitVecUtils.indexOf(&nextPkt, 0, pktsToSend, 
				     DELUGE_PKTS_PER_PAGE)) {
      // no more packets to send
      dbg(DBG_USR1, "DELUGE: SEND_DONE\n");
      changeState(S_IDLE);
      return;
    }
    pDataMsg->pktNum = (uint8_t)nextPkt;
    
    offset = calcOffset(pDataMsg->pgNum, pDataMsg->pktNum);      

    if (call DataRead.read(vars.tx.imgToSend, offset, pDataMsg->data, 
			   DELUGE_PKT_PAYLOAD_SIZE) == FAIL)
      post retrySetupDataMsg();

  }

  event result_t ReqTimer.fired() {

    TOS_MsgPtr pMsgBuf = call SharedMsgBuf.getMsgBuf();
    DelugeReqMsg* pReqMsg = (DelugeReqMsg*)(pMsgBuf->data);

    if (state != S_RECEIVING && state != S_RX_LOCKING)
      return SUCCESS;

    if (state == S_RX_LOCKING) {
      if (call SharedMsgBuf.lock() == FAIL) {
	call ReqTimer.start(TIMER_ONE_SHOT, DELUGE_FAILED_SEND_DELAY);	
	return SUCCESS;
      }
      // update address of source node
      changeState(S_RECEIVING);
      pReqMsg->dest = vars.rx.dataSourceAddr;
      pReqMsg->sourceAddr = TOS_LOCAL_ADDRESS;
      vars.rx.numReqTriesLeft = DELUGE_MAX_NUM_REQ_TRIES;
      pReqMsg->imgNum = workingImgNum;
      pReqMsg->pgNum = workingPgNum;
      pReqMsg->vNum = call Metadata.getVNum(workingImgNum);
      memcpy(pReqMsg->requestedPkts, pktsToReceive, DELUGE_PKT_BITVEC_SIZE);
    }

    if (vars.rx.suppressReq) {
      // suppress request
      call ReqTimer.start(TIMER_ONE_SHOT, DELUGE_NACK_TIMEOUT +
			  call Random.rand() % DELUGE_NACK_TIMEOUT);
      vars.rx.suppressReq = FALSE;
      return SUCCESS;
    }

    if (vars.rx.numReqTriesLeft == 0) {
      // tried too many times, give up
      changeState(S_IDLE);
      return SUCCESS;
    }

    {
      uint16_t dest = (pReqMsg->dest == TOS_UART_ADDR) ? TOS_UART_ADDR : TOS_BCAST_ADDR;
      if (call SendReqMsg.send(dest, sizeof(DelugeReqMsg), pMsgBuf) == SUCCESS) {
	vars.rx.numReqTriesLeft--;
      }
      else {
	// send failed, wait a bit and try again
	call ReqTimer.start(TIMER_ONE_SHOT, DELUGE_FAILED_SEND_DELAY);
      }
    }

    return SUCCESS;

  }

  event TOS_MsgPtr ReceiveReqMsg.receive(TOS_MsgPtr pMsg) {

    DelugeReqMsg *rxReqMsg = (DelugeReqMsg*)(pMsg->data);
    imgnum_t tmpImgNum;
    pgnum_t  tmpPgNum;
    int i;

    dbg(DBG_USR1, "DELUGE: Received REQ_MSG(dest=%d,vNum=%d,imgNum=%d,pgNum=%d,pkts=%x)\n",
	rxReqMsg->dest, rxReqMsg->vNum, rxReqMsg->imgNum, rxReqMsg->pgNum, rxReqMsg->requestedPkts[0]);

    if (state == S_DISABLED)
      return pMsg;

    if (state == S_SENDING || state == S_TX_LOCKING) {
      tmpImgNum = vars.tx.imgToSend;
      tmpPgNum = vars.tx.pageToSend;
    }
    else {
      tmpImgNum = workingImgNum;
      tmpPgNum = workingPgNum;
    }

    if (rxReqMsg->imgNum < tmpImgNum
	|| (rxReqMsg->imgNum == tmpImgNum
	    && (rxReqMsg->vNum - call Metadata.getVNum(tmpImgNum) > 0
		|| (rxReqMsg->vNum == call Metadata.getVNum(tmpImgNum)
		    && rxReqMsg->pgNum < tmpPgNum)))) {
      if (state == S_SENDING || state == S_TX_LOCKING) {
	changeState(S_IDLE);
	memset(pktsToSend, 0x0, DELUGE_PKT_BITVEC_SIZE);
      }
    }

    if (rxReqMsg->dest != TOS_LOCAL_ADDRESS) {
      if ((state == S_RECEIVING || state == S_RX_LOCKING)
	  && rxReqMsg->imgNum == workingImgNum
	  && rxReqMsg->vNum == call Metadata.getVNum(workingImgNum)
	  && rxReqMsg->pgNum <= workingPgNum) {
	// suppress next request since similar request has been overheard
	vars.rx.suppressReq = TRUE;
      }
      return pMsg;
    }

    if (rxReqMsg->pgNum >= call Metadata.getNumPgsComplete(rxReqMsg->imgNum)
	|| rxReqMsg->vNum != call Metadata.getVNum(rxReqMsg->imgNum)) {
      // don't have this page, ignore request
      return pMsg;
    }

    if (state == S_IDLE
	|| ((state == S_SENDING || state == S_TX_LOCKING)
	    && rxReqMsg->imgNum == vars.tx.imgToSend
	    && rxReqMsg->vNum == call Metadata.getVNum(vars.tx.imgToSend)
	    && rxReqMsg->pgNum == vars.tx.pageToSend)) {
      // take union of packet bit vectors
      for ( i = 0; i < DELUGE_PKT_BITVEC_SIZE; i++ )
	pktsToSend[i] |= rxReqMsg->requestedPkts[i];
    }

    if (state == S_IDLE) {
      // not currently sending, so start sending data
      changeState(S_TX_LOCKING);
      vars.tx.imgToSend = rxReqMsg->imgNum;
      vars.tx.pageToSend = rxReqMsg->pgNum;
      vars.tx.dest = (rxReqMsg->sourceAddr != TOS_UART_ADDR) ? TOS_BCAST_ADDR : TOS_UART_ADDR;
      setupDataMsg();
    }

    return pMsg;

  }

  task void writeData() {
    if (call DataWrite.write(workingImgNum, calcOffset(workingPgNum, receivedData.pktNum),
			     receivedData.data, DELUGE_PKT_PAYLOAD_SIZE) == FAIL)
      post writeData();
  }

  event TOS_MsgPtr ReceiveDataMsg.receive(TOS_MsgPtr pMsg) {

    TOS_MsgPtr pMsgBuf = call SharedMsgBuf.getMsgBuf();
    DelugeReqMsg *pReqMsg = (DelugeReqMsg*)(pMsgBuf->data);
    DelugeDataMsg *rxDataMsg = (DelugeDataMsg*)(pMsg->data);
    uint16_t tmp;

    dbg(DBG_USR1, "DELUGE: Received DATA_MSG(vNum=%d,imgNum=%d,pgNum=%d,pktNum=%d)\n",
	rxDataMsg->vNum, rxDataMsg->imgNum, rxDataMsg->pgNum, rxDataMsg->pktNum);

    if (state == S_DISABLED)
      return pMsg;

    if (workingImgNum == DELUGE_INVALID_IMGNUM)
      return pMsg;

    if (rxDataMsg->vNum == call Metadata.getVNum(workingImgNum)
	&& rxDataMsg->imgNum == workingImgNum
	&& rxDataMsg->pgNum <= workingPgNum) {
      
      if (state == S_RECEIVING || state == S_RX_LOCKING) {
	// suppress next request since nodes are still sending
	vars.rx.suppressReq = TRUE;
      }

      if (receivedData.pktNum == DELUGE_INVALID_PKTNUM
	  && rxDataMsg->pgNum == workingPgNum
	  && rxDataMsg->pktNum < DELUGE_PKTS_PER_PAGE
	  && BITVEC_GET(pktsToReceive, rxDataMsg->pktNum)) {
	// got a packet we need
	call Leds.set(rxDataMsg->pktNum);

	dbg(DBG_USR1, "DELUGE: SAVING(pgNum=%d,pktNum=%d)\n", 
	    rxDataMsg->pgNum,rxDataMsg->pktNum);
	
	// copy data
	receivedData.pktNum = rxDataMsg->pktNum;
	memcpy(receivedData.data, rxDataMsg->data, DELUGE_PKT_PAYLOAD_SIZE);
	if (call DataWrite.write(workingImgNum, calcOffset(workingPgNum, receivedData.pktNum),
				 receivedData.data, DELUGE_PKT_PAYLOAD_SIZE) == FAIL)
	  post writeData();

	// mark packet as received in request packet
	BITVEC_CLEAR(pktsToReceive, receivedData.pktNum);
	if (state == S_RECEIVING)
	  BITVEC_CLEAR(pReqMsg->requestedPkts, receivedData.pktNum);

	// stop requests if all packets are received
	if (!call BitVecUtils.indexOf(&tmp, 0, pktsToReceive, DELUGE_PKTS_PER_PAGE))
	  call ReqTimer.stop();
      }
    }

    return pMsg;

  }

  task void retrySendDataMsg() {

    if (state != S_SENDING)
      return;

    if (call SendDataMsg.send(vars.tx.dest, sizeof(DelugeDataMsg), 
			      call SharedMsgBuf.getMsgBuf()) == FAIL)
      post retrySendDataMsg();

  }

  event result_t DataRead.readDone(result_t result) {

    TOS_MsgPtr pMsgBuf = call SharedMsgBuf.getMsgBuf();

    if (state != S_SENDING)
      return SUCCESS;

    if (result == SUCCESS) {
      // success, begin sending
      if (call SendDataMsg.send(vars.tx.dest, sizeof(DelugeDataMsg), pMsgBuf) == FAIL)
	post retrySendDataMsg();
    }
    else {
      // fail, something bad happened forget sending
      changeState(S_IDLE);
    }

    return SUCCESS;

  }

/*
  task void checkCrc() {
    if (call StableStore.checkCrc(workingImgNum, workingPgNum,
				  receivedData.data) == FAIL)
      post checkCrc();
  }
*/  

  event result_t DataWrite.writeDone(result_t result) {

    uint16_t tmp;

    if (result == FAIL) {
      // fail, something bad happened, try again
      post writeData();
      return SUCCESS;
    }
    
    receivedData.pktNum = DELUGE_INVALID_PKTNUM;

    if (!call BitVecUtils.indexOf(&tmp, 0, pktsToReceive, DELUGE_PKTS_PER_PAGE)) {
      imgnum_t tmpImgNum = workingImgNum;
      pgnum_t  tmpPgNum = workingPgNum;
      workingImgNum = DELUGE_INVALID_IMGNUM;
      workingPgNum = DELUGE_INVALID_PGNUM;
      changeState(S_IDLE);
      signal PageTransfer.receivedPage(tmpImgNum, tmpPgNum);
      dbg(DBG_USR1, "DELUGE: RECEIVED_PAGE(pgNum=%d)\n", tmpPgNum);
/*
      if (call StableStore.checkCrc(workingImgNum, workingPgNum, dataQ[dataQHead].data) == FAIL)
      post checkCrc();
*/
    }
    
    return SUCCESS;

  }

  event result_t SendReqMsg.sendDone(TOS_MsgPtr pMsg, result_t success) {

    DelugeReqMsg* pReqMsg = (DelugeReqMsg*)(pMsg->data);

    if (state != S_RECEIVING)
      return SUCCESS;

    if (pReqMsg->imgNum == workingImgNum
 	&& pReqMsg->vNum == call Metadata.getVNum(workingImgNum)
	&& pReqMsg->pgNum == workingPgNum) {
      // start timeout timer in case request is not serviced
      call ReqTimer.start(TIMER_ONE_SHOT, 
	  		  DELUGE_NACK_TIMEOUT + call Random.rand() % DELUGE_NACK_TIMEOUT);
    }

    return SUCCESS;

  }

  event result_t SendDataMsg.sendDone(TOS_MsgPtr pMsg, result_t success) {

    DelugeDataMsg* pDataMsg = (DelugeDataMsg*)(pMsg->data);

    BITVEC_CLEAR(pktsToSend, pDataMsg->pktNum);
    if (pDataMsg->pktNum == DELUGE_PKTS_PER_PAGE - 1)
      pDataMsg->pktNum = 0;

    setupDataMsg();

    return SUCCESS;

  }

  event result_t DataWrite.eraseDone(result_t result) { return SUCCESS; }
  event result_t Metadata.setupNewImageDone(result_t result) { return SUCCESS; }

  event result_t SharedMsgBuf.bufFree() { return SUCCESS; }

}

--- NEW FILE: DelugeStorage.nc ---

interface DelugeStorage {
  command uint32_t imgNum2Addr(imgnum_t imgNum);
  command imgnum_t addr2ImgNum(uint32_t addr);
}

--- NEW FILE: DelugeStorageC.nc ---

includes FlashVolume;

configuration DelugeStorageC {
  provides {
    interface StdControl;
    interface DelugeDataRead as DataRead[uint8_t id];
    interface DelugeDataWrite as DataWrite[uint8_t id];
    interface DelugeMetadataRead as MetadataRead[uint8_t id];
    interface DelugeMetadataWrite as MetadataWrite[uint8_t id];
    interface DelugeStorage;
  }
}
implementation {

  components
    DelugeStorageM as Storage,
    BlockStorageC,
    FlashVolumeC;
    
  StdControl = Storage;
  StdControl = FlashVolumeC;
  DataRead = Storage;
  DataWrite = Storage;
  DelugeStorage = Storage;
  MetadataRead = Storage;
  MetadataWrite = Storage;

  Storage.SubControl -> BlockStorageC;
  Storage.Image0Volume -> FlashVolumeC.FlashVolume[DELUGE_IMAGE0_VOLUME];
  Storage.Image1Volume -> FlashVolumeC.FlashVolume[DELUGE_IMAGE1_VOLUME]; 
  Storage.Image0Read -> BlockStorageC.BlockRead[DELUGE_IMAGE0_VOLUME];
  Storage.Image1Read -> BlockStorageC.BlockRead[DELUGE_IMAGE1_VOLUME];
  Storage.Image0Write -> BlockStorageC.BlockWrite[DELUGE_IMAGE0_VOLUME];
  Storage.Image1Write -> BlockStorageC.BlockWrite[DELUGE_IMAGE1_VOLUME];

}

--- NEW FILE: DelugeStorageM.nc ---

module DelugeStorageM {
  provides {
    interface StdControl;
    interface DelugeMetadataRead as MetadataRead[uint8_t id];
    interface DelugeMetadataWrite as MetadataWrite[uint8_t id];
    interface DelugeDataRead as DataRead[uint8_t id];
    interface DelugeDataWrite as DataWrite[uint8_t id];
    interface DelugeStorage;
  }
  uses {
    interface BlockRead as Image0Read;
    interface BlockRead as Image1Read;
    interface BlockWrite as Image0Write;
    interface BlockWrite as Image1Write;
    interface FlashVolume as Image0Volume;
    interface FlashVolume as Image1Volume;
    interface StdControl as SubControl;
  }
}

implementation {

  enum {
    S_IDLE,
    S_READ_METADATA,
    S_WRITE_METADATA,
    S_READ_DATA,
    S_WRITE_DATA,
    S_ERASE_DATA,
  };

  uint8_t compID;
  uint8_t state;

  void actualSignal(result_t result) {
    uint8_t tmpState = state;
    state = S_IDLE;
    switch(tmpState) {
    case S_READ_DATA: signal DataRead.readDone[compID](result); break;
    case S_WRITE_DATA: signal DataWrite.writeDone[compID](result); break;
    case S_ERASE_DATA: signal DataWrite.eraseDone[compID](result); break;
    case S_READ_METADATA: signal MetadataRead.readDone[compID](result); break;
    case S_WRITE_METADATA: signal MetadataWrite.writeDone[compID](result); break;
    }
  }

  task void signalSuccess() { actualSignal(SUCCESS); }
  task void signalFail() { actualSignal(FAIL); }

  result_t signalDone(result_t result) {
    if (result == SUCCESS)
      post signalSuccess();
    else
      post signalFail();
    return SUCCESS;
  }

  command result_t StdControl.init() { 
    return call SubControl.init();
  }

  command result_t StdControl.start() { 
    call Image0Volume.mount(FV_FACTORY_IMAGE);
    call Image1Volume.mount(0);
    return call SubControl.start();
  }

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

  command uint32_t DelugeStorage.imgNum2Addr(imgnum_t imgNum) {
    uint32_t addr;
    switch(imgNum) {
    case 0: addr = call Image0Volume.physicalAddr(0); break;
    case 1: addr = call Image1Volume.physicalAddr(0); break;
    default: return DELUGE_INVALID_ADDR;
    }
    return addr + (uint32_t)DELUGE_DATA_OFFSET + (uint32_t)DELUGE_CRC_BLOCK_SIZE;
  }

  command imgnum_t DelugeStorage.addr2ImgNum(uint32_t addr) {
    return 0xffff;
  }

  result_t read(imgnum_t imgNum, block_addr_t addr, void* buf, block_addr_t len) {
    switch(imgNum) {
    case 0: return call Image0Read.read(addr, buf, len);
    case 1: return call Image1Read.read(addr, buf, len);
    }
    return FAIL;
  }

  result_t write(imgnum_t imgNum, block_addr_t addr, void* buf, block_addr_t len) {
    switch(imgNum) {
    case 0: return call Image0Write.write(addr, buf, len);
    case 1: return call Image1Write.write(addr, buf, len);
    }
    return FAIL;
  }

  result_t erase(imgnum_t imgNum) {
    switch(imgNum) {
    case 0: return call Image0Write.erase();
    case 1: return call Image1Write.erase();
    }
    return FAIL;
  }

  result_t newRequest(uint8_t newState, uint8_t id, imgnum_t imgNum, 
		      block_addr_t addr, void* buf, block_addr_t len) {

    result_t result;

    if (state != S_IDLE)
      return FAIL;

    if (imgNum >= DELUGE_NUM_IMAGES)
      return FAIL;

    compID = id;

    state = newState;
    switch(newState) {
    case S_READ_METADATA: case S_READ_DATA:
      result = read(imgNum, addr, buf, len);
      break;
    case S_WRITE_METADATA: case S_WRITE_DATA:
      result = write(imgNum, addr, buf, len);
      break;
    case S_ERASE_DATA:
      result = erase(imgNum);
      break;
    default:
      result = FAIL;
      break;
    }

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

    return SUCCESS;

  }

  command result_t MetadataRead.read[uint8_t id](imgnum_t imgNum, DelugeImgDesc* imgDesc) {
    return newRequest(S_READ_METADATA, id, imgNum, 0, imgDesc, sizeof(DelugeImgDesc));
  }

  command result_t MetadataWrite.write[uint8_t id](imgnum_t imgNum, DelugeImgDesc* imgDesc) {
    return newRequest(S_WRITE_METADATA, id, imgNum, 0, imgDesc, sizeof(DelugeImgDesc));
  }

  command result_t DataRead.read[uint8_t id](imgnum_t imgNum, block_addr_t addr,
					     uint8_t* buf, block_addr_t length) {
    return newRequest(S_READ_DATA, id, imgNum, DELUGE_DATA_OFFSET + addr, buf, length);
  }
  
  command result_t DataWrite.write[uint8_t id](imgnum_t imgNum, block_addr_t addr, 
					       uint8_t* buf, block_addr_t length) {
    return newRequest(S_WRITE_DATA, id, imgNum, DELUGE_DATA_OFFSET + addr, buf, length);
  }
  
  command result_t DataWrite.erase[uint8_t id](imgnum_t imgNum) {
    return newRequest(S_ERASE_DATA, id, imgNum, 0, 0, 0);
  }

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

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

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

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

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

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

  event result_t Image0Read.verifyDone(result_t result) { return SUCCESS; }
  event result_t Image0Write.commitDone(result_t result) { return SUCCESS; }
  event result_t Image1Read.verifyDone(result_t result) { return SUCCESS; }
  event result_t Image1Write.commitDone(result_t result) { return SUCCESS; }

  default event result_t DataRead.readDone[uint8_t id](result_t result) { return SUCCESS; }
  default event result_t DataWrite.writeDone[uint8_t id](result_t result) { return SUCCESS; }
  default event result_t DataWrite.eraseDone[uint8_t id](result_t result) { return SUCCESS; }
  default event result_t MetadataRead.readDone[uint8_t id](result_t result) { return SUCCESS; }
  default event result_t MetadataWrite.writeDone[uint8_t id](result_t result) { return SUCCESS; }


}

--- NEW FILE: NetProg.h ---
// $Id: NetProg.h,v 1.1 2004/11/22 05:30:57 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."
 *
 */

/**
 * Allows rebooting of multiple images.
 *
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

#ifndef __NETPROG_H__
#define __NETPROG_H__

#define IFLASH_LOCALID_ADDR   0x50
#define IFLASH_GROUPID_ADDR   0x52
#define IFLASH_CHECKSUM_ADDR  0x54

#define NETPROG_DISABLE_WDT()    WDTCTL = WDTPW + WDTHOLD;
#define NETPROG_ACTUAL_REBOOT()  WDTCTL = WDT_ARST_1_9; while(1);

#endif

--- NEW FILE: NetProg.nc ---
// $Id: NetProg.nc,v 1.1 2004/11/22 05:30:57 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."
 *
 */

/**
 * Top level interface for network programming integration with
 * applications.
 *
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

interface NetProg {

  /**
   * Reboot the node.
   *
   * @return  Does not return.
   */
  command result_t reboot();

  /**
   * Reboot into the image specified by <code>imgNum</code>. This
   * assumes that an image has been downloaded into slot <code>imgNum</code>
   * using Deluge.
   *
   * @param imgNum  Number of image to boot in to.
   * @return        <code>FAIL</code> if the reboot command fails to 
   *                complete due to an invalid imgNum or incomplete 
   *                image, 
   *                does not return, otherwise.
   */
  command result_t programImgAndReboot(uint8_t imgNum);

  /**
   * Get the image number currently executing.
   *
   * @return        The image number of the executing image,
   *                <code>DELUGE_INVALID_IMGNUM</code> otherwise.
   */
  command uint8_t  getExecutingImgNum();

}

--- NEW FILE: NetProgC.nc ---

includes NetProg;
includes TOSBoot;
#ifndef PLATFORM_PC
includes InternalFlash;
#endif

configuration NetProgC {
  provides {
    interface NetProg;
    interface StdControl;
  }
}

implementation {

  components
    DelugeMetadataC as Metadata,
    DelugeStorageC as Storage,
    NetProgM;

#ifndef PLATFORM_PC
  components InternalFlashC as IFlash;
  NetProgM.IFlash -> IFlash;
#endif

  StdControl = NetProgM;

  NetProg = NetProgM;
  
  NetProgM.Metadata -> Metadata.Metadata[unique("DelugeMetadata")];
  NetProgM.MetadataControl -> Metadata;
  NetProgM.Storage -> Storage;

}

--- NEW FILE: NetProgM.nc ---

module NetProgM {
  provides {
    interface NetProg;
    interface StdControl;
  }
  uses {
    interface DelugeMetadata as Metadata;
    interface DelugeStorage as Storage;
    interface InternalFlash as IFlash;
    interface SplitControl as MetadataControl;
  }
}

implementation {

  imgnum_t imgNum;

  uint8_t checkSum(uint16_t _addr, uint8_t _group) {
    return ~(_addr + _group);
  }

  void writeTOSinfo() {
    uint8_t checksum = checkSum(TOS_LOCAL_ADDRESS, TOS_AM_GROUP);
    call IFlash.write((uint8_t*)IFLASH_GROUPID_ADDR, &TOS_AM_GROUP, sizeof(TOS_AM_GROUP));
    call IFlash.write((uint16_t*)IFLASH_LOCALID_ADDR, &TOS_LOCAL_ADDRESS, sizeof(TOS_LOCAL_ADDRESS));
    call IFlash.write((uint8_t*)IFLASH_CHECKSUM_ADDR, &checksum, sizeof(checkSum));
  }

  command result_t StdControl.init() {
 
    // grab addr, pid, and gid from internal flash
    uint16_t addr, startPage;
    uint8_t group, sum;
    result_t result;

    result = call MetadataControl.init();

#ifndef PLATFORM_PC
    call IFlash.read((uint16_t*)TOSBOOT_CUR_IMG_START_ADDR, &startPage, sizeof(startPage));
    call IFlash.read((uint16_t*)IFLASH_LOCALID_ADDR, &addr, sizeof(addr));
    call IFlash.read((uint8_t*)IFLASH_GROUPID_ADDR, &group, sizeof(group));
    call IFlash.read((uint8_t*)IFLASH_CHECKSUM_ADDR, &sum, sizeof(sum));
    if (sum == checkSum(addr, group)) {
      TOS_AM_GROUP = group;
      atomic TOS_LOCAL_ADDRESS = addr;
    }
    else {
      writeTOSinfo();
    }

    imgNum = (startPage == 0xffff) ? DELUGE_INVALID_IMGNUM : 0;
    //call Storage.flashPage2ImgNum(startPage);
#else
    imgNum = DELUGE_INVALID_IMGNUM;
#endif
    return result;
  }
  
  command result_t StdControl.start() { 
    return call MetadataControl.start();
  }

  command result_t StdControl.stop() { return SUCCESS; }
  
  void markExplicitRebootFlag() {
#ifndef PLATFORM_PC
    uint8_t tmp;
    call IFlash.read((uint8_t*)TOSBOOT_FLAGS_ADDR, &tmp, sizeof(tmp));
    tmp |= TOSBOOT_EXPLICIT_REBOOT;
    call IFlash.write((uint8_t*)TOSBOOT_FLAGS_ADDR, &tmp, sizeof(tmp));
#endif
  }

  event result_t MetadataControl.initDone() { return SUCCESS; }
  event result_t MetadataControl.startDone() { return SUCCESS; }
  event result_t MetadataControl.stopDone() { return SUCCESS; }

  command result_t NetProg.reboot() {
#ifndef PLATFORM_PC
    atomic {
      NETPROG_DISABLE_WDT();
      writeTOSinfo();
      markExplicitRebootFlag();
      NETPROG_ACTUAL_REBOOT();
    }
#endif
    return FAIL;
  }

  command result_t NetProg.programImgAndReboot(imgnum_t newImgNum) {

    if (call Metadata.isComplete(newImgNum)) {
#ifndef PLATFORM_PC
      uint32_t imageAddr;
      uint8_t  tmp = 0;
      
      atomic {
	NETPROG_DISABLE_WDT();
	writeTOSinfo();
	markExplicitRebootFlag();
	
	imageAddr = call Storage.imgNum2Addr(newImgNum) + DELUGE_IDENT_SIZE;
	call IFlash.write((uint16_t*)TOSBOOT_NEW_IMG_START_ADDR, &imageAddr, sizeof(imageAddr));
	call IFlash.write((uint8_t*)TOSBOOT_LOAD_IMG_ADDR, &tmp, sizeof(tmp));
	
	// reboot
	NETPROG_ACTUAL_REBOOT();
      }
#endif
    }

    // image is not complete or invalid, or metadata is not ready
    return FAIL;

  }

  command uint8_t NetProg.getExecutingImgNum() { return imgNum; }

  event result_t Metadata.setupNewImageDone(result_t result) { return SUCCESS; }

}

--- NEW FILE: SharedMsgBuf.nc ---
// $Id: SharedMsgBuf.nc,v 1.1 2004/11/22 05:30:57 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."
 *
 */

/**
 * Simple component that allows sharing of message buffers through a
 * parameterized interface.
 *
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

interface SharedMsgBuf {

  /**
   * Get the pointer to a shared message buf.
   *
   * @return The pointer to the shared message buf.
   */
  command TOS_MsgPtr getMsgBuf();

  /**
   * Request a lock on the shared message buf.
   *
   * @return <code>SUCCESS</code> if the lock was acquired successfully;
   *         <code>FAIL</code> otherwise.
   */
  command result_t lock();

  /**
   * Release lock on shared message buf.
   *
   * @return <code>SUCCESS</code> if the lock was released successfully;
   */
  command result_t unlock();

  /**
   * Check if shared message buf is currently locked.
   *
   * @return <code>TRUE</code> if the shared message buf is locked;
   *         <code>FALSE</code> otherwise.
   */
  command bool isLocked();

  /**
   * Signal that the bus is free to allow other components waiting to
   * begin using it right away.
   *
   * @return <code>SUCCESS</code> on success,
   *         <code>FAIL</code> otherwise.
   */
  event result_t bufFree();

}

--- NEW FILE: SharedMsgBufM.nc ---
// $Id: SharedMsgBufM.nc,v 1.1 2004/11/22 05:30:57 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."
 *
 */

/**
 * Simple component that allows sharing of message * buffers through a
 * parameterized interface.
 *
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

module SharedMsgBufM {
  provides {
    interface SharedMsgBuf[uint8_t id];
    interface StdControl;
  }
  uses interface BitVecUtils;
}

implementation {

#include <BitVecUtils.h>

  enum {
    SMB_NUM_BUFS = uniqueCount("SharedMsgBuf"),
    SMB_LOCK_BITVEC_SIZE = (((SMB_NUM_BUFS-1)/8)+1),
  };

  TOS_Msg msgBufs[SMB_NUM_BUFS];
  uint8_t lockedMsgBufs[SMB_LOCK_BITVEC_SIZE];

  command result_t StdControl.init() {
    memset(lockedMsgBufs, 0x0, SMB_LOCK_BITVEC_SIZE);
    return SUCCESS;
  }
  
  command result_t StdControl.start() { return SUCCESS; }
  command result_t StdControl.stop() { return SUCCESS; }

  command TOS_MsgPtr SharedMsgBuf.getMsgBuf[uint8_t id]() {
    if (id >= SMB_NUM_BUFS)
      return NULL;
    return &(msgBufs[id]);
  }

  command result_t SharedMsgBuf.lock[uint8_t id]() {
    if (id >= SMB_NUM_BUFS || BITVEC_GET(lockedMsgBufs, id))
      return FAIL;
    BITVEC_SET(lockedMsgBufs, id);
    return SUCCESS;
  }

  command result_t SharedMsgBuf.unlock[uint8_t id]() {
    if (id >= SMB_NUM_BUFS)
      return FAIL;
    BITVEC_CLEAR(lockedMsgBufs, id);
    return SUCCESS;
  }

  command bool SharedMsgBuf.isLocked[uint8_t id]() {
    if (BITVEC_GET(lockedMsgBufs, id))
      return TRUE;
    return FALSE;
  }

  default event result_t SharedMsgBuf.bufFree[uint8_t id]() { return SUCCESS; }

}



More information about the Tinyos-beta-commits mailing list