[Tinyos-beta-commits] CVS: tinyos-1.x/beta/Drain Drain.h, NONE, 1.1 DrainC.nc, NONE, 1.1 DrainLinkEst.nc, NONE, 1.1 DrainLinkEstM.nc, NONE, 1.1 DrainM.nc, NONE, 1.1

Gilman Tolle gtolle at users.sourceforge.net
Mon Feb 14 15:16:39 PST 2005


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

Added Files:
	Drain.h DrainC.nc DrainLinkEst.nc DrainLinkEstM.nc DrainM.nc 
Log Message:
First checkin of Drain -- untested

--- NEW FILE: Drain.h ---
// $Id: Drain.h,v 1.1 2005/02/14 23:16:37 gtolle Exp $

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

/**
 * @author Gilman Tolle
 */


#ifndef __DRAIN_H__
#define __DRAIN_H__

enum {
  AM_DRAINMSG = 4,
  AM_DRAINBEACONMSG = 5,
};

enum {
  DRAIN_QUEUE_SIZE = 3,
  DRAIN_MAX_RETRANSMITS = 5,
  DRAIN_MAX_MISSED_BEACONS = 5,
  DRAIN_UNKNOWN_ACK_EST = 127,
};

typedef struct DrainMsg {
  uint16_t sourceaddr;
  uint16_t originaddr;
  uint8_t ttl;
  uint8_t type;
  uint8_t data[0];
} DrainMsg;

typedef struct DrainBeaconMsg {
  uint16_t parent;
  uint16_t sourceAddr;
  uint16_t cost;
  uint16_t treeID;
  uint32_t timestamp;
  uint16_t beaconPeriod;
  uint8_t  beaconSeqno;
  uint8_t  level;
} DrainBeaconMsg;

#endif



--- NEW FILE: DrainC.nc ---
includes Drain;

configuration DrainC {
  
  provides {
    interface StdControl;

    interface Send[uint8_t id];
    interface Receive[uint8_t id];
    interface Intercept[uint8_t id];
    interface Intercept as Snoop[uint8_t id];
  }
}

implementation {

  components 
    DrainM, 
    DrainLinkEstM,
    GenericComm, 
    RandomLFSR,
    TimerC,
    LedsC as Leds;
  
#if defined(PLATFORM_MICA2) || defined(PLATFORM_MICA2DOT) || defined(PLATFORM_XSM)
  components CC1000RadioC as RadioC;
#elif defined(PLATFORM_TELOS) || defined (PLATFORM_TELOSB)
  components CC2420RadioC as RadioC;
#endif
  
  StdControl = DrainM.StdControl;
  Receive = DrainM.Receive;
  Send = DrainM.Send;
  Intercept = DrainM.Intercept;
  Snoop = DrainM.Snoop;
  
  DrainM.SubControl -> GenericComm;
  DrainM.SubControl -> DrainLinkEstM;

  DrainM.Leds -> Leds;

  DrainM.DrainLinkEst -> DrainLinkEstM;

  DrainM.SendMsg -> GenericComm.SendMsg[AM_DRAINMSG];
  DrainM.ReceiveMsg -> GenericComm.ReceiveMsg[AM_DRAINMSG];

#ifndef PLATFORM_PC
  DrainM.MacControl -> RadioC.MacControl;
#endif

  DrainLinkEstM.Timer -> TimerC.Timer[unique("Timer")];
  DrainLinkEstM.AgingTimer -> TimerC.Timer[unique("Timer")];  

  DrainLinkEstM.Random -> RandomLFSR;

  DrainLinkEstM.SendMsg -> GenericComm.SendMsg[AM_DRAINBEACONMSG];
  DrainLinkEstM.ReceiveMsg -> GenericComm.ReceiveMsg[AM_DRAINBEACONMSG];
}







--- NEW FILE: DrainLinkEst.nc ---
// $Id: DrainLinkEst.nc,v 1.1 2005/02/14 23:16:37 gtolle Exp $

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

/**
 * @author Gilman Tolle
 */

interface DrainLinkEst {

  /**
   * Whether there is currently a valid route.
   *
   * @return Whether there is a valid route.
   */
  command bool isActive();

  /**
   * Given a TOS_MsgPtr, initialize its routing fields to a known
   * state, specifying that the message is originating from this node.
   * This known state can then be used by selectRoute() to fill in
   * the necessary data.
   *
   * @param msg Message to select route for and fill in init data.
   *
   * @return Should always return SUCCESS.
   *
   */

  command result_t initializeFields(TOS_MsgPtr msg, uint8_t id);
  
  /**
   * Select a route and fill in all of the necessary routing
   * information to a packet.
   *
   * @param msg Message to select route for and fill in routing information.
   *
   * @return Whether a route was selected succesfully. On FAIL the
   * packet should not be sent.
   *
   */
  
  command result_t selectRoute(TOS_MsgPtr msg, uint8_t id, bool firstTime);

  /**
   * Inform the link estimator that the message has been sent,
   * possibly successfully, possibly not.
   *
   */

  command result_t messageSent(TOS_MsgPtr msg, uint8_t id, result_t success);
}

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



/*
 * Authors:          Gilman Tolle
 */


module DrainLinkEstM {

  provides {
    interface StdControl;
    interface DrainLinkEst;
  }

  uses {
    interface Timer;
    interface Timer as AgingTimer;

    interface Random;

    interface SendMsg;
    interface ReceiveMsg;
  }
}

implementation {

  int8_t   beaconSeqno;
  uint8_t  missedBeacons;
  uint16_t beaconPeriod;

  uint16_t currentTreeID;
  uint16_t currentParentAddr;
  uint16_t currentParentCost;
  uint16_t currentParentLinkEst;
  uint16_t currentParentLQI;
  uint16_t currentParentAckEst;
  uint8_t  currentDepth;
  uint16_t successCounter;
  uint16_t failCounter;

  bool msgBufBusy;
  TOS_Msg buf;

#define MAX(a_,b_) (a_ > b_ ? a_ : b_)
#define MIN(a_,b_) (a_ < b_ ? a_ : b_)

  uint16_t adjustLQI(uint8_t val);
  task void SendRouteTask();

  command result_t StdControl.init() {
    
    msgBufBusy = FALSE;
    
#ifdef PLATFORM_PC
    currentParentAddr = TOS_LOCAL_ADDRESS-1; // For debugging.
#else
    currentParentAddr = TOS_BCAST_ADDR;
#endif
    currentParentCost = 0xffff;
    currentParentLinkEst = 0xffff;
    currentParentAckEst = DRAIN_UNKNOWN_ACK_EST;
    currentParentLQI = 0x0;
    currentTreeID = 0;
    currentDepth = 0;

    beaconSeqno = 1;
    missedBeacons = 0;

    successCounter = failCounter = 0;

    return SUCCESS;
  }

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

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

  command result_t DrainLinkEst.initializeFields(TOS_MsgPtr Msg, uint8_t id) {
    DrainMsg *pMHMsg = (DrainMsg *)&Msg->data[0];

    pMHMsg->sourceaddr = TOS_LOCAL_ADDRESS;
    pMHMsg->originaddr = TOS_LOCAL_ADDRESS;
    pMHMsg->ttl = 16;
    pMHMsg->type = id;

    return SUCCESS;
  }

  command result_t DrainLinkEst.selectRoute(TOS_MsgPtr Msg, uint8_t id, 
					    bool firstTime) {
    DrainMsg *pMHMsg = (DrainMsg *)&Msg->data[0];
    
    Msg->addr = currentParentAddr;
    pMHMsg->sourceaddr = TOS_LOCAL_ADDRESS;

    if (firstTime) {
      pMHMsg->ttl--;
    }

    if (pMHMsg->ttl == 0) {
	return FAIL;
    } else {
      return SUCCESS;
    }
  }

  event TOS_MsgPtr ReceiveMsg.receive(TOS_MsgPtr Msg) {

    DrainBeaconMsg *pRP = (DrainBeaconMsg *)&Msg->data[0];

    /* 
       If we already belong to the newest tree we know of, consider
       the beacon seqno.  If it is newer, send out our own beacon.
    */
    
    if ((int8_t)(pRP->beaconSeqno - beaconSeqno) > 0 
	|| pRP->beaconSeqno == 0) {
      
      if (pRP->beaconSeqno == 0) {
	beaconSeqno++;
	if (beaconSeqno == 0)
	  beaconSeqno++;
      }	else {
	beaconSeqno = pRP->beaconSeqno;
      }
      
      if (pRP->beaconPeriod != beaconPeriod) {
	beaconPeriod = pRP->beaconPeriod;
	call AgingTimer.stop();
	call AgingTimer.start(TIMER_ONE_SHOT,
			      1024 * beaconPeriod);
      }
      call Timer.start(TIMER_ONE_SHOT, 
		       (call Random.rand() % (1024 * beaconPeriod)) + 1);
    }
    
    /* Now evaluate whether we should reparent to the beacon. */
      
    if (pRP->sourceAddr == currentParentAddr) {

      uint16_t newLinkEst; 
     
      currentTreeID = pRP->treeID;
      currentParentCost = pRP->cost;

#ifdef PLATFORM_TELOS
      newLinkEst = adjustLQI(Msg->lqi);
      currentParentLQI = Msg->lqi;
#else
      newLinkEst = Msg->strength;
#endif

      currentParentLinkEst = newLinkEst;

      missedBeacons = 0;

      currentDepth = pRP->level + 1;

    } else {

      /* if the message is not from my parent, 
	 compare the message's cost + link estimate to my current cost,
	 switch if necessary */

      uint32_t currentQuality = 
	(uint32_t) currentParentCost + (uint32_t) currentParentLinkEst; 
      uint16_t newLinkEst;
      uint32_t newQuality = pRP->cost;
      
#ifdef PLATFORM_TELOS
      newLinkEst = adjustLQI(Msg->lqi);
      newQuality += (uint32_t) adjustLQI(Msg->lqi);
#else
      newLinkEst = Msg->strength;
      newQuality += (uint32_t) Msg->strength;
#endif
      
#ifdef NO_ACK_EST
      // do nothing
#else
      currentQuality += (uint32_t) currentParentAckEst;
      newQuality += (uint32_t) DRAIN_UNKNOWN_ACK_EST;
#endif

      if (newQuality < currentQuality && pRP->parent != TOS_LOCAL_ADDRESS) {
	
	currentTreeID = pRP->treeID;
	currentParentAddr = pRP->sourceAddr;
	currentParentCost = pRP->cost;
	currentParentLinkEst = newLinkEst;
	currentParentAckEst = DRAIN_UNKNOWN_ACK_EST;
#ifdef PLATFORM_TELOS
	currentParentLQI = Msg->lqi;
#endif
	currentDepth = pRP->level + 1;
	successCounter = 0;
	failCounter = 0;
      }
    }

    return Msg;
  }

  uint16_t adjustLQI(uint8_t val) {
    uint16_t result = (80 - (val - 50));
    result = (((result * result) >> 3) * result) >> 3;
    return result;
  }

  event result_t Timer.fired() {
    post SendRouteTask();
    return SUCCESS;
  }

  task void SendRouteTask() {
    TOS_MsgPtr pMsgBuf = &buf;
    DrainBeaconMsg *pRP = (DrainBeaconMsg *)&pMsgBuf->data[0];
    uint8_t length = sizeof(DrainBeaconMsg);

    dbg(DBG_ROUTE,"MultiHopRSSI Sending route update msg.\n");

    if (currentParentAddr != TOS_BCAST_ADDR) {
      dbg(DBG_ROUTE,"MultiHopRSSI: Parent = %d\n", currentParentAddr);
    }

    if (msgBufBusy) {
#ifndef PLATFORM_PC
      post SendRouteTask();
#endif
      return;
    }
    
    atomic msgBufBusy = TRUE;

    dbg(DBG_ROUTE,"MultiHopRSSI: Current cost: %d.\n", 
	currentParentCost + currentParentLinkEst);

    pRP->parent = currentParentAddr;
    pRP->sourceAddr = TOS_LOCAL_ADDRESS;
    pRP->cost = currentParentCost + currentParentLinkEst;
#ifndef NO_ACK_EST
    pRP->cost += currentParentAckEst;
#endif
    pRP->treeID = currentTreeID;
    pRP->beaconSeqno = beaconSeqno;
    pRP->beaconPeriod = beaconPeriod;
    pRP->level = currentDepth;

    if (!call SendMsg.send(TOS_BCAST_ADDR, length, pMsgBuf)) {
#ifndef PLATFORM_PC
      post SendRouteTask();
#else
      atomic msgBufBusy = FALSE;
#endif
    }
  }

  event result_t AgingTimer.fired() {
#ifndef NO_ACK_EST
    if (successCounter + failCounter > 0) {
      currentParentAckEst = (255 - (255 * successCounter) / (successCounter + failCounter));
      successCounter = failCounter = 0;
    }
#endif

    if (missedBeacons > DRAIN_MAX_MISSED_BEACONS) {
      if (currentParentLinkEst << 1 < 0xffff) {
	currentParentLinkEst <<= 1;
      } else {
	currentParentLinkEst = 0xffff;
      }
    }
    if (missedBeacons != 0xff) {
      missedBeacons++;
    }

    call AgingTimer.start(TIMER_ONE_SHOT, (1024 * beaconPeriod));
    return SUCCESS;
  }

  command bool DrainLinkEst.isActive() {
    if (currentParentAddr == TOS_BCAST_ADDR) {
      return FALSE;
    } else {
      return TRUE;
    }
  }
  
  command result_t DrainLinkEst.messageSent(TOS_MsgPtr msg, uint8_t id, 
					    result_t success) {
    if (success) {
      successCounter++; 
    } else {
      failCounter++;
    }
    return SUCCESS;
  }

  event result_t SendMsg.sendDone(TOS_MsgPtr pMsg, result_t success) {
    if (pMsg == &buf) {
      atomic msgBufBusy = FALSE;
    }
    return SUCCESS;
  }
}


--- NEW FILE: DrainM.nc ---

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

/**
 * @author Gilman Tolle
 */

module DrainM {
  provides {
    interface StdControl;
    interface Receive[uint8_t id];
    interface Send[uint8_t id];
    interface Intercept[uint8_t id];
    interface Intercept as Snoop[uint8_t id];
  }
  uses {
    interface StdControl as SubControl;

    interface Leds;

    interface ReceiveMsg;
    interface SendMsg;

    interface DrainLinkEst;

#ifndef PLATFORM_PC
    interface MacControl;
#endif
  }
}

implementation {

  enum {
    DRAIN_SEND_QUEUE_SIZE = DRAIN_QUEUE_SIZE, // Send Queue
    DRAIN_FWD_QUEUE_SIZE = DRAIN_QUEUE_SIZE, // Forwarding Queue
  };

  // Send Queue
  TOS_MsgPtr sendQueue[DRAIN_SEND_QUEUE_SIZE];
  uint8_t sendQueueIn, sendQueueOut;

  // Forward Queue
  TOS_Msg fwdBuffers[DRAIN_FWD_QUEUE_SIZE];
  TOS_MsgPtr fwdQueue[DRAIN_FWD_QUEUE_SIZE];
  uint8_t fwdQueueIn, fwdQueueOut;

  bool sendQueueFull;
  bool fwdQueueFull;
  bool queuesBusy;

  uint8_t maxRetransmits;
  uint8_t currentFailCount;

  task void QueueServiceTask();

  void initializeBufs();
  TOS_MsgPtr mForward(TOS_MsgPtr pMsg, uint8_t id);

  void inc(uint16_t *val);
  void clear(uint16_t *val);
  task void errorBlink();

  /***********************************************************************
   * Initialization 
   ***********************************************************************/

  command result_t StdControl.init() {
    initializeBufs();

#ifdef PLATFORM_PC
    maxRetransmits = 0;
#else
    maxRetransmits = DRAIN_MAX_RETRANSMITS;
#endif

    currentFailCount = 0;

    return call SubControl.init();
  }
  
  void initializeBufs() {
    int n;

    for (n=0; n < DRAIN_FWD_QUEUE_SIZE; n++) {
      fwdQueue[n] = &fwdBuffers[n];
    }

    fwdQueueIn = fwdQueueOut = 0;
    fwdQueueFull = FALSE;

    sendQueueIn = sendQueueOut = 0;
    sendQueueFull = FALSE;

    queuesBusy = FALSE;
  }

  command result_t StdControl.start() {
#ifndef PLATFORM_PC
    atomic call MacControl.enableAck();
#endif
    return call SubControl.start();
  }
 
  command result_t StdControl.stop() {
    return SUCCESS;
  }

  /***********************************************************************
   * Commands and events
   ***********************************************************************/

  command void* Send.getBuffer[uint8_t id](TOS_MsgPtr pMsg, uint16_t* length) {
    
    DrainMsg *pMHMsg = (DrainMsg *)pMsg->data;
    
    *length = TOSH_DATA_LENGTH - offsetof(DrainMsg,data);

    dbg(DBG_ROUTE, "Drain: getBuffer(pMsg=0x%x,id=%d,len=%d)\n",
	pMsg, id, *length);

    return (&pMHMsg->data[0]);
  }

  command result_t Send.send[uint8_t id](TOS_MsgPtr pMsg, uint16_t payloadLen) {
    uint16_t usMHLength = offsetof(DrainMsg,data) + payloadLen;

    dbg(DBG_ROUTE, "Drain: send(pMsg=0x%x,id=%d,len=%d)\n",
	pMsg, id, payloadLen);

    if (usMHLength > TOSH_DATA_LENGTH) {
      return FAIL;
    }

    if (sendQueueFull) {
      dbg(DBG_ROUTE, "Drain: sendQueueFull(pMsg=0x%x,id=%d,len=%d)\n",
	  pMsg, id, payloadLen);
      return FAIL;
    }

    call DrainLinkEst.initializeFields(pMsg, id);

    if (call DrainLinkEst.selectRoute(pMsg, id, TRUE) != SUCCESS) {
      dbg(DBG_ROUTE, "Drain: sendSelectRouteFail(pMsg=0x%x,id=%d,len=%d)\n",
	  pMsg, id, payloadLen);
      return FAIL;
    }

    dbg(DBG_ROUTE, "Drain: sendEnterQueue(pMsg=0x%x,id=%d,len=%d)\n",
	pMsg, id, payloadLen);

    pMsg->length = usMHLength;

    if (!queuesBusy) {
      if (post QueueServiceTask() == FAIL) {
	return FAIL;
      } else {
	queuesBusy = TRUE;
      }
    }
      
    sendQueue[sendQueueIn] = pMsg;
    sendQueueIn = (sendQueueIn + 1) % DRAIN_SEND_QUEUE_SIZE;
    if (sendQueueIn == sendQueueOut)
      sendQueueFull = TRUE;

    return SUCCESS;
  } 

  event TOS_MsgPtr ReceiveMsg.receive(TOS_MsgPtr pMsg) {
    
    DrainMsg *pMHMsg = (DrainMsg *)pMsg->data;
    uint16_t payloadLen = pMsg->length - offsetof(DrainMsg,data);
    uint8_t id = pMHMsg->type;
    
    dbg(DBG_ROUTE, "Drain: receive(pMsg=0x%x,src=0x%02x,org=0x%02x)\n", 
        pMsg, pMHMsg->sourceaddr, pMHMsg->originaddr);

    signal Snoop.intercept[id](pMsg, &pMHMsg->data[0], payloadLen);

    if (pMsg->addr == TOS_LOCAL_ADDRESS) { // Addressed to local node

      if ((signal Intercept.intercept[id](pMsg, 
					  &pMHMsg->data[0], 
					  payloadLen)) == SUCCESS) {

	dbg(DBG_ROUTE, "Drain: forward(pMsg=0x%x,src=0x%02x,org=0x%02x)\n", 
	    pMHMsg->sourceaddr, pMHMsg->originaddr);

        pMsg = mForward(pMsg, id);
      }
    }
    
    return pMsg;
  }

  TOS_MsgPtr mForward(TOS_MsgPtr pMsg, uint8_t id) {

    TOS_MsgPtr	pNewBuf = pMsg;

    if (fwdQueueFull) {
      dbg(DBG_ROUTE, "Drain: forwardQueueFull(pMsg=0x%x)\n", pMsg);
      return pMsg;
    }

    if (call DrainLinkEst.selectRoute(pMsg, id, TRUE) != SUCCESS) {
      dbg(DBG_ROUTE, "Drain: forwardSelectRouteFail(pMsg=0x%x)\n", pMsg);
      return pMsg;
    }
    
    pNewBuf = fwdQueue[fwdQueueIn];
    fwdQueue[fwdQueueIn] = pMsg;
    fwdQueueIn = (fwdQueueIn + 1) % DRAIN_FWD_QUEUE_SIZE;
    if (fwdQueueIn == fwdQueueOut)
      fwdQueueFull = TRUE;

    dbg(DBG_ROUTE, "Drain: forwardEnterQueue(pMsg=0x%x)\n", pMsg);
    
    if (!queuesBusy) {
      if (post QueueServiceTask()) {
	queuesBusy = TRUE;
      }
    }

    return pNewBuf;
  }

  task void QueueServiceTask() {

    TOS_MsgPtr pMsg;

    dbg(DBG_ROUTE, "Drain: queueServiceTask\n");

    // First check send queue. 
    if (sendQueueIn != sendQueueOut || 
	(sendQueueIn == sendQueueOut && sendQueueFull == TRUE)) {

      dbg(DBG_ROUTE, "Drain: queueServiceTask(servicing=sendQueue)\n");
      
      // We've got a message in the send queue.
      pMsg = sendQueue[sendQueueOut];

      pMsg->ack = 0;

      if (call SendMsg.send(pMsg->addr, pMsg->length, pMsg) == SUCCESS) {
	// Wait for the sendDone.
      } else {
	// The radio didn't accept our message.
	post QueueServiceTask();
      }

    // Then check forward queue. 
    } else if (fwdQueueIn != fwdQueueOut || 
	       (fwdQueueIn == fwdQueueOut && fwdQueueFull == TRUE)) {

      dbg(DBG_ROUTE, "Drain: queueServiceTask(servicing=forwardQueue)\n");

      // We've got a message in the forward queue.
      pMsg = fwdQueue[fwdQueueOut];

      pMsg->ack = 0;

      if (call SendMsg.send(pMsg->addr, pMsg->length, pMsg) == SUCCESS) {
	// Wait for the sendDone.
      } else {
	// The radio didn't accept our message.
	post QueueServiceTask();
      }      

    } else {
      
      dbg(DBG_ROUTE, "Drain: queueServiceTask(queuesAllEmpty)\n");
      queuesBusy = FALSE;
      return;
    }
  }

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

    result_t forwardResultVal = SUCCESS;
    DrainMsg* mhMsg = (DrainMsg*) pMsg->data;

    dbg(DBG_ROUTE, "Drain: sendDone(pMsg=0x%x,success=%d)\n", 
	pMsg, success);  

    if (pMsg != sendQueue[sendQueueOut] && 
	pMsg != fwdQueue[fwdQueueOut]) 
      return SUCCESS;

    if (!success) {
      post QueueServiceTask();
      return SUCCESS;
    }

    if (pMsg->addr == TOS_BCAST_ADDR) {
      // It didn't have a destination. Don't try retransmitting.

    } else {

      // It did have a destination. Consider retransmitting.
      
      if (pMsg->ack == 0) {

	// It wasn't acked.
	call DrainLinkEst.messageSent(pMsg, pMsg->type, FAIL);
	currentFailCount++;

	if (maxRetransmits > 0 && currentFailCount < maxRetransmits) {

	  // See if we should retransmit
	  if (call DrainLinkEst.selectRoute(pMsg, pMsg->type, FALSE) == SUCCESS) {
	    post QueueServiceTask();
	    return SUCCESS;
	  }

	} else {

	  // We've tried to retransmit too many times. Give up.
	  forwardResultVal = FAIL;
	}

      } else {
	
	// It was acked.
	call DrainLinkEst.messageSent(pMsg, pMsg->type, SUCCESS);
      }
    }
    
    dbg(DBG_ROUTE, "Drain: sendComplete(pMsg=0x%x,result=%d)\n", 
	pMsg, forwardResultVal);
    
    if (pMsg == sendQueue[sendQueueOut]) {

      signal Send.sendDone[mhMsg->type](pMsg, forwardResultVal);

      sendQueueOut = (sendQueueOut + 1) % DRAIN_SEND_QUEUE_SIZE;
      if (sendQueueFull)
	sendQueueFull = FALSE;
      currentFailCount = 0;
      post QueueServiceTask();

    } else if (pMsg == fwdQueue[fwdQueueOut]) {

      fwdQueueOut = (fwdQueueOut + 1) % DRAIN_SEND_QUEUE_SIZE;
      if (fwdQueueFull)
	fwdQueueFull = FALSE;
      currentFailCount = 0;
      post QueueServiceTask();

    } else {

      dbg(DBG_ROUTE, "Drain: ERROR! RECEIVED SEND DONE FOR MESSAGE NOT IN QUEUE (pMsg=0x%x)\n", pMsg);
    }
    
    return SUCCESS;
  }

  default event result_t Send.sendDone[uint8_t id](TOS_MsgPtr pMsg, 
						   result_t success) {
    return SUCCESS;
  }

  default event result_t Intercept.intercept[uint8_t id](TOS_MsgPtr pMsg, 
							 void* payload, 
							 uint16_t payloadLen) {
    return SUCCESS;
  }

  default event result_t Snoop.intercept[uint8_t id](TOS_MsgPtr pMsg, 
						     void* payload, 
                                                     uint16_t payloadLen) {
    return SUCCESS;
  }
}




More information about the Tinyos-beta-commits mailing list