/*
 * smac.cc
 * Copyright (C) 2000 by the University of Southern California
 * $Id: smac.cc,v 1.17 2005/08/25 18:58:07 johnh Exp $
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 *
 *
 * The copyright of this module includes the following
 * linking-with-specific-other-licenses addition:
 *
 * In addition, as a special exception, the copyright holders of
 * this module give you permission to combine (via static or
 * dynamic linking) this module with free software programs or
 * libraries that are released under the GNU LGPL and with code
 * included in the standard release of ns-2 under the Apache 2.0
 * license or under otherwise-compatible licenses with advertising
 * requirements (or modified versions of such code, with unchanged
 * license).  You may copy and distribute such a system following the
 * terms of the GNU GPL for this module and the licenses of the
 * other code concerned, provided that you include the source code of
 * that other code when and as the GNU GPL requires distribution of
 * source code.
 *
 * Note that people who make modified versions of this module
 * are not obligated to grant this special exception for their
 * modified versions; it is their choice whether to do so.  The GNU
 * General Public License gives permission to release a modified
 * version without this exception; this exception also makes it
 * possible to release a modified version which carries forward this
 * exception.
 *
 */

// smac is designed and developed by Wei Ye (SCADDS/ISI)
// and is re-written for ns by Padma Haldar (CONSER/ISI).
// Contributors: Yuan Li

// This module implements Sensor-MAC
//  http://www.isi.edu/scadds/papers/smac_report.pdf
//
// It has the following functions.
//  1) Both virtual and physical carrier sense
//  2) RTS/CTS for hidden terminal problem
//  3) Backoff and retry
//  4) Broadcast packets are sent directly without using RTS/CTS/ACK.
//  5) A long unicast message is divided into multiple TOS_MSG (by upper
//     layer). The RTS/CTS reserves the medium for the entire message.
//     ACK is used for each TOS_MSG for immediate error recovery.
//  6) Node goes to sleep when its neighbor is communicating with another
//     node.
//  7) Each node follows a periodic listen/sleep schedule
//  8.1) At bootup time each node listens for a fixed SYNCPERIOD and then
//     tries to send out a sync packet. It suppresses sending out of sync pkt
//     if it happens to receive a sync pkt from a neighbor and follows the
//     neighbor's schedule.
//  8.2) Or a node can choose its own schecule instead of following others, the
//       schedule start time is user configurable
//  9) Neighbor Discovery: in order to prevent that two neighbors can not
//     find each other due to following complete different schedules, each
//     node periodically listen for a whole period of the SYNCPERIOD
//  10) Duty cycle is user configurable

//  New features including adaptive listen
//   See http://www.isi.edu/~weiye/pub/smac_ton.pdf
                                                                                                                                                           
#include "wireless-phy.h"
#include "smac.h"

static class MacSmacClass : public TclClass {
public:
       MacSmacClass() : TclClass("Mac/SMAC") {}
	TclObject* create(int, const char*const*) {
		return (new SMAC());
	}
} class_macSMAC;


// Timers call on expiration

int SmacTimer::busy()
{
	if (status_ != TIMER_PENDING)
		return 0;
	else
		return 1;
}

#ifdef JOURNAL_PAPER
void SmacUpdateNeighbTimer::expire(Event *e) {
        a_->handleUpdateNeighbTimer();
}
                                                                                                                                                            
void SmacAdaptiveListenTimer::expire(Event *e) {
        a_->handleAdaptiveListenTimer();
}
#endif

void SmacGeneTimer::expire(Event *e) {
	a_->handleGeneTimer();
}

void SmacRecvTimer::expire(Event *e) {
	stime_ = rtime_ = 0;
	a_->handleRecvTimer();
}

void SmacRecvTimer::sched(double time) {
	TimerHandler::sched(time);
	stime_ = Scheduler::instance().clock();
	rtime_ = time;
}

void SmacRecvTimer::resched(double time) {
	TimerHandler::resched(time);
	stime_ = Scheduler::instance().clock();
	rtime_ = time;
}

double SmacRecvTimer::timeToExpire() {
	return ((stime_ + rtime_) - Scheduler::instance().clock());
}

void SmacSendTimer::expire(Event *e) {
	a_->handleSendTimer();
}

void SmacNavTimer::expire(Event *e) {
	a_->handleNavTimer();
}

void SmacNeighNavTimer::sched(double time) {
	TimerHandler::sched(time);
	stime_ = Scheduler::instance().clock();
	rtime_ = time;
}

void SmacNeighNavTimer::expire(Event *e) {
	stime_ = rtime_ = 0;
	a_->handleNeighNavTimer();
}

double SmacNeighNavTimer::timeToExpire() {
	return ((stime_ + rtime_) - Scheduler::instance().clock());
}

void SmacCsTimer::expire(Event *e) {
	a_->handleCsTimer();
}

// if pending, cancel timer
void SmacCsTimer::checkToCancel() {
	if (status_ == TIMER_PENDING)
		cancel();
}

// void SmacChkSendTimer::expire(Event *e) {
//   a_->handleChkSendTimer();
// }

void SmacCounterTimer::sched(double time) {
	// the cycle timer assumes that all time shall be scheduled with time "left to sleep" 
	// and not the absolute time for a given state (sleep, sync or data). Thus inorder 
	// to schedule for a sleep state, need to schedule with aggregate time CYCLETIME 
	// (sleeptime+synctime+dadatime).
	// Similarly for sync state, schedule with listenTime_ (synctime+datattime)
	// This is implemented to be in step with the counter used in actual smac.

	tts_ = time; // time before it goes to sleep again
	stime_ = Scheduler::instance().clock();
  
	if (time <= CLKTICK2SEC(cycleTime_) && time > CLKTICK2SEC(listenTime_)) { // in sleep state
		value_ = sleepTime_;
		if (status_ == TIMER_IDLE)
			TimerHandler::sched(time - CLKTICK2SEC(listenTime_)); 
		else
			TimerHandler::resched(time - CLKTICK2SEC(listenTime_)); 
    
	} else if ( time <= CLKTICK2SEC(listenTime_) && time > CLKTICK2SEC(dataTime_)) { // in sync state
		value_ = syncTime_;
		if (status_ == TIMER_IDLE)
			TimerHandler::sched(time - CLKTICK2SEC(dataTime_)); 
		else
			TimerHandler::resched(time - CLKTICK2SEC(dataTime_)); 
    
	} else { // in data state
		assert(time <= CLKTICK2SEC(dataTime_));
		value_ = dataTime_;
		if (status_ == TIMER_IDLE)
			TimerHandler::sched(time); 
		else
			TimerHandler::resched(time); 
    
	}

}

double SmacCounterTimer::timeToSleep() {
	return ((stime_ + tts_) - Scheduler::instance().clock()) ;
}

void SmacCounterTimer::expire(Event *e) {
	tts_ = stime_ = 0;
	a_->handleCounterTimer(index_);
}


#ifdef JOURNAL_PAPER
SMAC::SMAC() : Mac(), mhUpdateNeighb_(this),mhNav_(this), mhNeighNav_(this), mhSend_(this), mhRecv_(this), mhGene_(this), mhCS_(this), mhAdap_(this), syncFlag_(0) {
        int i;
#else
SMAC::SMAC() : Mac(), mhNav_(this), mhNeighNav_(this), mhSend_(this), mhRecv_(this), mhGene_(this), mhCS_(this), syncFlag_(0) {
#endif
	state_ = IDLE;
	radioState_ = RADIO_IDLE;
	tx_active_ = 0;
	mac_collision_ = 0;
  
	sendAddr_ = -1;
	recvAddr_ = -1;

	nav_ = 0;
	neighNav_ = 0;
  
	numRetry_ = 0;
	numExtend_ = 0;
	lastRxFrag_ = -3; // since -1, -2 and 0 could be valid pkt uid's
	//numFrags_ = 0;
	//succFrags_ = 0;

#ifdef JOURNAL_PAPER
        numFrags_ = 0;
        succFrags_ = 0;
        dataSched_ = 0;
        syncSched_ = 0;
                                                                                                                                                            
        globalSchedule_ = 0; // Do not test global schedule
        //globalSchedule_ = 1; // Test global schedule
                                                                                                                                                            
        updateNeighbList_ = 0;
                                                                                                                                                            
        sendSYNCFlag_ = 0;
                                                                                                                                                            
        sendAddr = -1;
        adapSend_ = 0;
        txRequest_ = 0;
                                                                                                                                                            
        adaptiveListen_ = 0;
#endif

	dataPkt_ = 0;
	pktRx_ = 0;
	pktTx_ = 0;

	/* setup internal mac and physical parameters
	   ----------------------------------------------
	   byte_tx_time_: time to transmit a byte, in ms. Derived from bandwidth
  
	   slotTime_: time of each slot in contention window. It should be large
	   enough to receive the whole start symbol but cannot be smaller than clock 
	   resolution. in msec
  
	   slotTime_sec_: slottime in sec
  
	   difs_: DCF interframe space (from 802.11), in ms. It is used at the beginning
	   of each contention window. It's the minmum time to wait to start a new 
	   transmission.
  
	   sifs_: short interframe space (f

	   /rom 802.11), in ms. It is used before sending
	   an CTS or ACK packet. It takes care of the processing delay of each pkt.
  
	   eifs_: Entended interfrane space (from 802.11) in ms. Used for backing off 
	   incase of a collision.

	   guardTime_: guard time at the end of each listen interval, in ms.

	*/

	byte_tx_time_ = 8.0 / BANDWIDTH;
	double start_symbol = byte_tx_time_ * 2.5;  // time to tx 20 bits
	slotTime_ = CLOCKRES >= start_symbol ? CLOCKRES : start_symbol;  // in msec
	slotTime_sec_ = slotTime_ / 1.0e3;   // in sec
	difs_ = 10.0 * slotTime_;
	sifs_ = 5.0 * slotTime_;
	eifs_ = 50.0 * slotTime_;
	guardTime_ = 4.0 * slotTime_;
  
	// calculate packet duration. Following equations assume 4b/6b coding.
	// All calculations yield in usec

	//durSyncPkt_ = ((SIZEOF_SMAC_SYNCPKT) * 12 + 18) / 1.0e4 ;

	durSyncPkt_ =  (PRE_PKT_BYTES + (SIZEOF_SMAC_SYNCPKT * ENCODE_RATIO)) * byte_tx_time_ + 1;
	durSyncPkt_ = CLKTICK2SEC(durSyncPkt_);

	//durDataPkt_ = ((SIZEOF_SMAC_DATAPKT) * 12 + 18) / 1.0e4 ;
	durDataPkt_ = (PRE_PKT_BYTES + (SIZEOF_SMAC_DATAPKT * ENCODE_RATIO)) * byte_tx_time_ + 1;
	durDataPkt_ = CLKTICK2SEC(durDataPkt_);

	//durCtrlPkt_ = ((SIZEOF_SMAC_CTRLPKT) * 12 + 18) / 1.0e4;
	durCtrlPkt_ = (PRE_PKT_BYTES + (SIZEOF_SMAC_CTRLPKT * ENCODE_RATIO)) * byte_tx_time_ + 1;
	durCtrlPkt_ = CLKTICK2SEC(durCtrlPkt_);
  
	// time to wait for CTS or ACK
	//timeWaitCtrl_ = durCtrlPkt_ + CLKTICK2SEC(4) ;    // timeout time
	double delay = 2 * PROC_DELAY + sifs_;
	timeWaitCtrl_ = CLKTICK2SEC(delay) + durCtrlPkt_;    // timeout time

  
	numSched_ = 0;
	numNeighb_ = 0;
	numSync_ = 1;  // perform neighbor discovery, do not go to sleep for the first SYNC period
	schedListen_ = 1;
	searchNeighb_ = 1;

#ifdef JOURNAL_PAPER
        schedState_ = 1;  // this is my first schedule
	
	// initialize neighbour table
        for (i = 0; i < SMAC_MAX_NUM_NEIGHBORS; i++) {
		neighbList_[i].nodeId = 0;
		neighbList_[i].schedId = 0;
		neighbList_[i].active = 0;
                neighbList_[i].state = 0;
        }
                                                                                                                                                            
        // initialize schedule table
        for (i = 0; i < SMAC_MAX_NUM_SCHEDULES; i++) {
                schedTab_[i].numNodes = 0;
                schedTab_[i].syncNode = 0;
        }
                                                                                                                                                            
                                                                                                                                                            
        schedTab_[0].numNodes = 1;  // I'm the only one on this schedule
        schedTab_[0].syncNode = index_;  // I'm the schedule initializer
        schedTab_[0].txData = 0;
        schedTab_[0].txSync = 0;
        schedTab_[0].chkSched = 0;
#endif
		
	Tcl& tcl = Tcl::instance();
	tcl.evalf("Mac/SMAC set syncFlag_");
	if (strcmp(tcl.result(), "0") != 0)  
		syncFlag_ = 1;              // syncflag is set; use sleep-wakeup cycle


	tcl.evalf("Mac/SMAC set selfConfigFlag_");
        if (strcmp(tcl.result(), "0") != 0)
                selfConfigFlag_ = 1;              // autoflag is set; user can not configure the schedule start time

	
	// User can specify the duty cycle
	tcl.evalf("Mac/SMAC set dutyCycle_");
	if (strcmp(tcl.result(), "0") != 0){
                bind_bw("dutyCycle_", &dutyCycle_);
               	//printf("dutyCyle=%f\n", dutyCycle_);
	
	}
        else {
//               	dutyCycle_ = SMAC_DUTY_CYCLE;
	}

	if (!syncFlag_)
		txData_ = 0;
  
	else {
		// Calculate sync/data/sleeptime based on duty cycle
		// all time in ms
		syncTime_ = difs_ + slotTime_ * SYNC_CW + SEC2CLKTICK(durSyncPkt_) + guardTime_;
#ifdef JOURNAL_PAPER
                // added time for overhearing CTS so that can do adaptive listen
                dataTime_ = difs_ + slotTime_ * DATA_CW + SEC2CLKTICK(durCtrlPkt_) + PROC_DELAY + sifs_ + SEC2CLKTICK(durCtrlPkt_) + guardTime_;
#else
		dataTime_ = difs_ + slotTime_ * DATA_CW + SEC2CLKTICK(durCtrlPkt_) + guardTime_;
#endif
		listenTime_ = syncTime_ + dataTime_;
		cycleTime_ = listenTime_ * 100 / dutyCycle_ + 1;
		sleepTime_ = cycleTime_ - listenTime_;
    
		//printf("cycletime=%d, sleeptime=%d, listentime=%d\n", cycleTime_, sleepTime_, listenTime_);


		for (int i=0; i< SMAC_MAX_NUM_SCHEDULES; i++) {
			mhCounter_[i] = new SmacCounterTimer(this, i);
			mhCounter_[i]->syncTime_ = syncTime_;
			mhCounter_[i]->dataTime_ = dataTime_;
			mhCounter_[i]->listenTime_ = listenTime_;
			mhCounter_[i]->sleepTime_ = sleepTime_;
			mhCounter_[i]->cycleTime_ = cycleTime_;
		}

		// printf("syncTime= %d, dataTime= %d, listentime = %d, sleepTime= %d, cycletime= %d\n", syncTime_, dataTime_, listenTime_, sleepTime_, cycleTime_);

		// listen for a whole period to choose a schedule first
		//double cw = (Random::random() % SYNC_CW) * slotTime_sec_ ;
  
		// The foll (higher) CW value allows neigh nodes to follow a single schedule
		// double w = (Random::random() % (SYNC_CW)) ;
		// double cw = w/10.0;
		double c = CLKTICK2SEC(listenTime_) + CLKTICK2SEC(sleepTime_);
		double s = SYNCPERIOD + 1;
		double t = c * s ;
		//mhGene_.sched(t + cw);

		if ( selfConfigFlag_ == 1) {
#ifdef JOURNAL_PAPER
                adapTime_ = dataTime_;
                mhGene_.sched(t);
                                                                                                                                                            
                //start setting timer for update neighbor list
                //printf("SMAC_UPDATE_NEIGHB_PERIOD: ............node %d %d at %.6f\n", index_, SMAC_UPDATE_NEIGHB_PERIOD, Scheduler::instance().clock());
                mhUpdateNeighb_.sched(SMAC_UPDATE_NEIGHB_PERIOD);
                //dump();
#else
		mhGene_.sched(t);
#endif
		}
	}
}

void SMAC::setMySched(Packet *pkt) 
{
	// set my schedule and put it into the first entry of schedule table
	state_ = IDLE;
	numSched_ = 1;
	schedTab_[0].numPeriods = 0;
	schedTab_[0].txData = 0;
	schedTab_[0].txSync = 1; // need to brdcast my schedule
  
	if (pkt == 0) { // freely choose my schedule
#ifdef JOURNAL_PAPER
                //printf("#############################################################\n");
                //printf(" %d is choosing its own shedule %d \n", index_, index_);
                //printf("#############################################################\n");
                schedState_++;
                mhCounter_[0]->sched(CLKTICK2SEC(listenTime_+index_*10));
                schedTab_[0].syncNode = index_;
#else
		mhCounter_[0]->sched(CLKTICK2SEC(listenTime_));
#endif
		mySyncNode_ = index_; // myself
		currSched_ = 0;
		//sendSYNC();  
    
	} else { // follow schedule in syncpkt
    
		struct smac_sync_frame *pf = (struct smac_sync_frame *)pkt->access(hdr_mac::offset_);

		mhCounter_[0]->sched(pf->sleepTime);
#ifdef JOURNAL_PAPER
                mySyncNode_ = pf->syncNode;
                //printf("#############################################################\n");
                //printf("%d receives SYNC packet from %d and starts following shedule %d \n", index_, pf->srcAddr, pf->syncNode);
                //printf("#############################################################\n");
                schedTab_[0].numNodes++;  // 2 nodes on this schedule now
                schedTab_[0].syncNode = pf->syncNode;
                schedState_++;
                                                                                                                                                            
                //add node in my neighbor list
                neighbList_[0].nodeId = pf->srcAddr;
                neighbList_[0].schedId = 0;
                neighbList_[0].active = 1;
                neighbList_[0].state = pf->state;
#else
		mySyncNode_ = pf->srcAddr;    
		//add node in my neighbor list
		neighbList_[0].nodeId = mySyncNode_;
		neighbList_[0].schedId = 0;
#endif
		numNeighb_ = 1;
	}
}



int SMAC::command(int argc, const char*const* argv)
{
	if (argc == 3) {
		if (strcmp(argv[1], "log-target") == 0) {
			logtarget_ = (NsObject*) TclObject::lookup(argv[2]);
			if(logtarget_ == 0)
				return TCL_ERROR;
			return TCL_OK;
		}
		else if ( selfConfigFlag_ != 1) {
			if (strcmp(argv[1], "schedule-start-time") == 0) {

	                        startTime_ = strtod(argv[2],NULL);

                        	// set up schedule
	                        state_ = IDLE;
        	                numSched_ = 1;
                	        schedTab_[0].numPeriods = SYNCPERIOD;
                        	schedTab_[0].txData = 0;
	                        schedTab_[0].txSync = 1; // need to brdcast my schedule

        	                // schedule starts up with listen time (sync+data)
                	        // need to caculate time to sleep

                        	startTime_ = startTime_ + listenTime_;
	                        if ( startTime_ >= cycleTime_ )
        	                        startTime_ = startTime_ - cycleTime_;

                	        mhCounter_[0]->sched(CLKTICK2SEC(startTime_));
                        	mySyncNode_ = index_; // myself

	                        currSched_ = 0;

        	                return TCL_OK;
		
                	}

		}
	}

	return Mac::command(argc, argv);

}

#ifdef JOURNAL_PAPER
void SMAC::adaptiveListen()
{
        // adaptively wake-up at the end of current transmission. Will try to
        // send only if the buffered packet is unicast. Since my next-hop
        // neighbor may not be aware of the Tx of my previous-hop neighbor,
        // broadcast now is unreliable
        //printf("adaptiveListen set AdaptiveTimer: node %d scheduletime: %f adapTime_: %d time:%.9f \n", index_, mhCounter_[0]->value_, adapTime_, Scheduler::instance().clock());
        mhAdap_.resched(CLKTICK2SEC(adapTime_)); // set timer to bring me back to sleep
        adaptiveListen_ = 1;
        if (state_ == SLEEP) {
                //printf("adaptiveListen wakeup: node %d scheduletime: %f time:%.9f \n", index_, mhCounter_[0]->value_, Scheduler::instance().clock());
                wakeup();
        }
         else {
        }
                                                                                                                                                            
        if ( schedTab_[0].txData == 1 && sendAddr == UNICAST_ADDR){
                adapSend_ = 1;
                checkToSend();
        }
}
#endif

// XXXX smac handler functions

void SMAC::handleSendTimer() {
	assert(pktTx_);
  
	struct hdr_smac *sh = HDR_SMAC(pktTx_);
  
	// Packet tx is done so radio should go back to idle
	radioState_ = RADIO_IDLE;
	tx_active_ = 0;
  
	switch(sh->type) {
    
	case RTS_PKT:
		sentRTS(pktTx_);
		break;

	case CTS_PKT:
		sentCTS(pktTx_);
		break;
    
	case DATA_PKT:
		sentDATA(pktTx_);
		break;
  
	case ACK_PKT:
		sentACK(pktTx_);
		break;
	case SYNC_PKT:
		sentSYNC(pktTx_);
		break;
	default:
		fprintf(stderr, "unknown mac pkt type, %d\n", sh->type);
		break;
	}
  
	pktTx_ = 0;
}


void SMAC::handleRecvTimer() {
	assert(pktRx_);
  
	struct hdr_cmn *ch = HDR_CMN(pktRx_);
	struct hdr_smac *sh = HDR_SMAC(pktRx_);

	if (state_ == SLEEP) {

		// Bug fixed here. a collision might happen just now, need to clear the mac_collision_ flag, otherwise the node won't receive any following packet

		if (mac_collision_) {
	                discard(pktRx_, DROP_MAC_COLLISION);
                	mac_collision_ = 0;
	                updateNav(CLKTICK2SEC(eifs_));

	                if (state_ == CR_SENSE)
        	                sleep(); // have to wait until next wakeup time
                	else
                        	radioState_ = RADIO_IDLE;

	                goto done;
                }

		discard(pktRx_, DROP_MAC_SLEEP);
		radioState_ = RADIO_SLP;
		goto done;
	}
  
	// if the radio interface is tx'ing when this packet arrives
	// I would never have seen it and should do a silent discard 
  
	if (radioState_ == RADIO_TX) {
		Packet::free(pktRx_);
		goto done;
	}
  
	if (mac_collision_) {
		discard(pktRx_, DROP_MAC_COLLISION);
		mac_collision_ = 0;
		updateNav(CLKTICK2SEC(eifs_));
    
		if (state_ == CR_SENSE) 
			sleep(); // have to wait until next wakeup time
		else 
			radioState_ = RADIO_IDLE;
    
		goto done;
	}
  
	if (ch->error()) {
		Packet::free(pktRx_);
		updateNav(CLKTICK2SEC(eifs_)); 

		if (state_ == CR_SENSE) 
			sleep();
		else 
			radioState_ = RADIO_IDLE;
      
		goto done;
	}
  
	// set radio from rx to idle again
	radioState_ = RADIO_IDLE;

	switch (sh->type) {
	case DATA_PKT:
		handleDATA(pktRx_);
		break;
	case RTS_PKT:
		handleRTS(pktRx_);
		Packet::free(pktRx_);
		break;
	case CTS_PKT:
		handleCTS(pktRx_);
		Packet::free(pktRx_);
		break;
	case ACK_PKT:
		handleACK(pktRx_);
		Packet::free(pktRx_);
		break;
	case SYNC_PKT:
		handleSYNC(pktRx_);
		Packet::free(pktRx_);
		break;
	default:
		fprintf(stderr, "Unknown smac pkt type, %d\n", sh->type);
		break;
	}
  
 done:
	pktRx_ = 0;
  
}

void SMAC::handleGeneTimer() 
{
  
	if (syncFlag_) {
		// still in choose-schedule state
		if (numSched_ == 0) {
			setMySched(0); // I'm the primary synchroniser
			return;
		} 
	}
	if (state_ == WAIT_CTS) {  // CTS timeout
		if (numRetry_ < SMAC_RETRY_LIMIT) {
			numRetry_++;
			// wait until receiver's next wakeup
			state_ = IDLE;
#ifdef JOURNAL_PAPER
			//node tries to go to sleep if it needs to resend
                	if( mhCounter_[0]->value_ == sleepTime_ )
                        	sleep();
#endif
 
			if (!syncFlag_)
				checkToSend();
      
		} else {
			state_ = IDLE;
			Packet::free(dataPkt_);
			dataPkt_ = 0;
			numRetry_ = 0;
			//numFrags_ = 0;
			// signal upper layer about failure of tx 
			// txMsgFailed();
			txMsgDone();
      
		}
    
	} else if (state_ == WAIT_ACK) { // ack timeout
    
		if (numExtend_ < SMAC_EXTEND_LIMIT) { // extend time
			printf("SMAC %d: no ACK received. Extend Tx time.\n", index_);
			numExtend_++;
      
			updateNeighNav(durDataPkt_ + durCtrlPkt_);
			//neighNav_ = (durDataPkt_ + durCtrlPkt_);
      
		} else { // reached extension limit, can't extend time
			//numFrags_--;
      
		}
		if (neighNav_ < (durDataPkt_ + durCtrlPkt_)) {
      
			// used up reserved time, stop tx
      
			discard(dataPkt_, DROP_MAC_RETRY_COUNT_EXCEEDED);
			dataPkt_ = 0;
			pktTx_ = 0;
			state_ = IDLE;
      
			// signal upper layer the number of transmitted frags
			//txMsgFailed(succFrags); -> no frag for now
      
			txMsgDone();
      
		} else { // still have time
			// keep sending until use up remaining time
			sendDATA();
		}

#ifdef JOURNAL_PAPER
        } else if (state_ == DATA_SENSE1) {
                state_ = DATA_SENSE2;
                mhGene_.resched(timeWaitCtrl_);
                                                                                                                                                            
        } else if (state_ == DATA_SENSE2) {
                state_ = IDLE;
		//node tries to go to sleep if it does not hear CTS or DATA for others' connection
                if( mhCounter_[0]->value_ == sleepTime_ )
                        sleep();
#endif
	}
}


void SMAC::handleNavTimer() {
	// medium is now free
	nav_ = 0; // why have this variable?? probably not required use the timer instead
  
	if (!syncFlag_) {
		if (state_ == SLEEP)
			wakeup();

		// try to send waiting data, if any
		checkToSend();
	} 
#ifdef JOURNAL_PAPER
        adaptiveListen();
#endif
}


int SMAC::checkToSend() {
#ifdef JOURNAL_PAPER
        if (txRequest_ == 1 || syncFlag_) {
#else
	if (txData_ == 1) {
#endif
		assert(dataPkt_);
		struct hdr_smac *mh = HDR_SMAC(dataPkt_);
    
		if (radioState_ != RADIO_SLP && radioState_ != RADIO_IDLE)
			goto done;  // cannot send if radio is sending or recving
    
		if (state_ != SLEEP && state_ != IDLE && state_ != WAIT_DATA )
			goto done; // cannot send if not in any of these states
    
		if (!(mhNav_.busy()) && !(mhNeighNav_.busy()) &&
		    (state_ == SLEEP || state_ == IDLE)) {
      
			if (state_ == SLEEP) wakeup();
      
			if ((u_int32_t)mh->dstAddr == MAC_BROADCAST)
				howToSend_ = BCASTDATA;
			else
				howToSend_ = UNICAST;
      
			state_ = CR_SENSE;

#ifdef JOURNAL_PAPER
                        adapSend_ = 0;
			//printf("adaptiveListen sendData: node %d scheduletime: %f time:%.9f \n", index_, mhCounter_[0]->value_, Scheduler::instance().clock());
#endif
    
			// start cstimer
			double cw = (Random::random() % DATA_CW) * slotTime_sec_;
			mhCS_.sched(CLKTICK2SEC(difs_) + cw);
      
			return 1;
    
		} else {
			return 0;
		}
    
	done:
		return 0;
    
	} else {
		return 0;
	}
}


void SMAC::handleNeighNavTimer() {
  
	// Timer to track my neighbor's NAV
	neighNav_ = 0;         // probably don't need to use this variable
  
	if (state_ == WAIT_DATA) { // data timeout
		state_ = IDLE;
    
		// signal upper layer that rx msg is done
		// didnot get any/all data
		rxMsgDone(0); 
	} else {
		if (!syncFlag_)
			checkToSend();
	}
#ifdef JOURNAL_PAPER
        adaptiveListen();
#endif
}


void SMAC::handleCsTimer() {
  
	// carrier sense successful
  
#ifdef MAC_DEBUG
	if (howToSend_ != BCASTSYNC && dataPkt_ == 0)
		numCSError++;
#endif // MAC_DEBUG
  
	switch(howToSend_) {
	case BCASTSYNC:
		if (sendSYNC())
			state_ = IDLE;
		break;
    
	case BCASTDATA:
		startBcast();
		break;
    
	case UNICAST:
		startUcast();
		break;
	}
}

void SMAC::handleCounterTimer(int id) {
  
	//printf("MAC:%d,id:%d - time:%.9f\n", index_,id,Scheduler::instance().clock());
#ifdef JOURNAL_PAPER
        if (schedTab_[id].numNodes > 0) {
#endif

	if (mhCounter_[id]->value_ == sleepTime_) { //woken up from sleep
		// listentime starts now

		if (radioState_ != RADIO_SLP && radioState_ != RADIO_IDLE)
			goto sched_1;  // cannot send if radio is sending or recving
    
		if (state_ != SLEEP && state_ != IDLE && state_ != WAIT_DATA )
			goto sched_1;; // cannot send if not in any of these states
    
		if (!(mhNav_.busy()) && !(mhNeighNav_.busy()) &&
		    (state_ == SLEEP || state_ == IDLE)) {
    
			if (state_ == SLEEP &&
			    (id == 0 || schedTab_[id].txSync == 1)) {
	
				wakeup();
			}
			if (schedTab_[id].txSync == 1) {
				// start carrier sense for sending sync
				howToSend_ = BCASTSYNC;
#ifdef JOURNAL_PAPER
				syncSched_ = id;
#else
				currSched_ = id;
#endif
				state_ = CR_SENSE;
				double cw = (Random::random() % SYNC_CW) * slotTime_sec_;
				mhCS_.sched(CLKTICK2SEC(difs_) + cw);
			}
		}
		// start to listen now
	sched_1:
		mhCounter_[id]->sched(CLKTICK2SEC(listenTime_));
    
	} else if (mhCounter_[id]->value_ == syncTime_) { //synctime over
		// can start datatime now
    
		if (radioState_ != RADIO_SLP && radioState_ != RADIO_IDLE)
			goto sched_2;  // cannot send if radio is sending or recving
    
		if (state_ != SLEEP && state_ != IDLE && state_ != WAIT_DATA )
			goto sched_2; // cannot send if not in any of these states
    
		if (schedTab_[id].txData == 1 &&
		    (!(mhNav_.busy()) && !(mhNeighNav_.busy())) &&
		    (state_ == SLEEP || state_ == IDLE)) {
			// schedule sending data
      
			if (state_ == SLEEP)
				wakeup();
      
			struct hdr_smac *mh = (struct hdr_smac *)dataPkt_->access(hdr_mac::offset_);
			if ((u_int32_t)mh->dstAddr == MAC_BROADCAST)
				howToSend_ = BCASTDATA;
			else
				howToSend_ = UNICAST;
#ifdef JOURNAL_PAPER
                        dataSched_ = id;
#else
			currSched_ = id;
#endif
			state_ = CR_SENSE;
			// start cstimer
			double cw = (Random::random() % DATA_CW) * slotTime_sec_;
			mhCS_.sched(CLKTICK2SEC(difs_) + cw);
		}
	sched_2:
		mhCounter_[id]->sched(CLKTICK2SEC(dataTime_));
    
	} else if (mhCounter_[id]->value_ == dataTime_) { //datatime over

		// check if in the middle of recving a pkt
		if (radioState_ == RADIO_RX)
			goto sched_3;
#ifdef JOURNAL_PAPER    
		if (id == 0 && state_ == IDLE && searchNeighb_ ==0 && adaptiveListen_ ==0 )
#else
		if (id == 0 && state_ == IDLE && searchNeighb_ ==0 )
#endif
			sleep();

	sched_3:
		// now time to go to sleep
		mhCounter_[id]->sched(CLKTICK2SEC(cycleTime_));
    
		// check if ready to send out sync 
		if (schedTab_[id].numPeriods > 0) {
			schedTab_[id].numPeriods--;
			if (schedTab_[id].numPeriods == 0) {
	
				schedTab_[id].txSync = 1; 

				// neighbor discovery
				if ( id == 0 ) {
					numSync_--;
				//	printf("numSync_ %d: ............node %d at %.6f\n", numSync_, index_,Scheduler::instance().clock());

					if ( numSync_ == 1 ) {
						searchNeighb_ = 1;	// node will go to neighbor discovery period starting from the next frame
						//printf("Start Neighbor Discovery: ............node %d at %.6f\n", index_, Scheduler::instance().clock());
					}
					else if ( numSync_ == 0 ) {
						searchNeighb_  = 0;  // neighbor discovery period lasts exactly one SYNC period
						//printf("Ending Neighbor Discovery: ............node %d at %.6f\n", index_, Scheduler::instance().clock());
						if ( numNeighb_ == 0 ) {
							numSync_ = SRCH_CYCLES_SHORT;
						}
						else {
							numSync_ = SRCH_CYCLES_LONG;

						}
					}		

				}	
			}
		}
	}
#ifdef JOURNAL_PAPER
    }
#endif
}

#ifdef JOURNAL_PAPER
void SMAC::handleUpdateNeighbTimer() {
        //printf("SMAC::handleUpdateNeighbTimer: ............node %d at %.6f\n", index_, Scheduler::instance().clock());
        if (txRequest_ == 0) { // No data waiting to be transmitted
                txRequest_ = 1; // temporarily disable tx when updating
                update_myNeighbList();
        } else {
                updateNeighbList_ = 1; // set flag to update when tx done
        }
}
                                                                                                                                                            
void SMAC::handleAdaptiveListenTimer() {
	//node tries to go to sleep after adaptive listen times out
        adaptiveListen_ = 0;
        if (state_ == IDLE && state_ != TX_PKT && mhCounter_[0]->value_ == sleepTime_)
                sleep();
}
#endif

// recv function for mac layer

void SMAC::recv(Packet *p, Handler *h) {
                                                                                                                                                            
	struct hdr_cmn *ch = HDR_CMN(p);

	assert(initialized());

	// handle outgoing pkt
	if ( ch->direction() == hdr_cmn::DOWN) {
		sendMsg(p, h);
		return;
	}

	// handle incoming pkt
	// we have just recvd the first bit of a pkt on the network interface  
  
	// if the interface is in tx mode it probably would not see this pkt
	if (radioState_ == RADIO_TX && ch->error() == 0) {
		assert(tx_active_);
		ch->error() = 1;
		pktRx_ = p;
		mhRecv_.resched(txtime(p));

		return;
	}
  
	// cancel carrier sense timer and wait for entire pkt
	if (state_ == CR_SENSE) {
		printf("Cancelling CS- node %d\n", index_);
		// cancels only if timer is pending; smac could be in CR_SENSE with timer cancelled
		// incase it has already received a pkt and receiving again
		mhCS_.checkToCancel();
	}
  
	// if the interface is already in process of recv'ing pkt
	if (radioState_ == RADIO_RX) {
		assert(pktRx_); 
		assert(mhRecv_.busy());
    
		// if power of the incoming pkt is smaller than the power 
		// of the pkt currently being recvd by atleast the capture 
		// threshold then we ignore the new pkt.
    
		if (pktRx_->txinfo_.RxPr / p->txinfo_.RxPr >= p->txinfo_.CPThresh) 
			capture(p);
		else
			collision(p);
	} 
  
	else {
		if (mhRecv_.busy()) { // and radiostate != RADIO_RX
			assert(radioState_ == RADIO_SLP);
			// The radio interface was recv'ing a pkt when it went to sleep
			// should it postpone sleep till it finishes recving the pkt???
			mhRecv_.resched(txtime(p));
		} else
			mhRecv_.sched(txtime(p));
    
		radioState_ = RADIO_RX;
		pktRx_ = p;
	}
}


void SMAC::capture(Packet *p) {
	// we update NAV for this pkt txtime
	updateNav(CLKTICK2SEC(eifs_) + txtime(p));
	Packet::free(p);
}


void SMAC::collision(Packet *p) {
	if (!mac_collision_)
		mac_collision_ = 1;
  
	// since a collision has occured figure out which packet that caused 
	// the collision will "last" longer. Make this pkt pktRx_ and reset the
	// recv timer.
	if (txtime(p) > mhRecv_.timeToExpire()) {
		mhRecv_.resched(txtime(p));
		discard(pktRx_, DROP_MAC_COLLISION);
		// shouldn't we free pkt here ???
		pktRx_ = p;

	}
	else 
		discard(p, DROP_MAC_COLLISION);
	// shouldn't we free pkt here ???
}


void SMAC::discard(Packet *p, const char* why)
{
	hdr_cmn *ch = HDR_CMN(p);
	hdr_smac *sh = HDR_SMAC(p);
  
	/* if the rcvd pkt contains errors, a real MAC layer couldn't
	   necessarily read any data from it, so we just toss it now */
	if(ch->error() != 0) {
		Packet::free(p);
		//p = 0;
		return;
	}

	switch(sh->type) {
    
	case RTS_PKT:
		if (drop_RTS(p, why))
			return;
		break;
    
	case CTS_PKT:
	case ACK_PKT:
		if (drop_CTS(p, why))
			return;
		break;
  
	case DATA_PKT:
		if (drop_DATA(p, why))
			return;
		break;

	case SYNC_PKT:
		if(drop_SYNC(p, why))
			return;
		break;

	default:
		fprintf(stderr, "invalid MAC type (%x)\n", sh->type);
		//trace_pkt(p);
		exit(1);
	}
	Packet::free(p);
}


int SMAC::drop_RTS(Packet *p, const char* why) 
{
	struct smac_control_frame *cf = (smac_control_frame *)p->access(hdr_mac::offset_);
  
	if (cf->srcAddr == index_) {
		drop(p, why);
		return 1;
	}
	return 0;
}

int SMAC::drop_CTS(Packet *p, const char* why) 
{
	struct smac_control_frame *cf = (smac_control_frame *)p->access(hdr_mac::offset_);

	if (cf->dstAddr == index_) {
		drop(p, why);
		return 1;
	}
	return 0;
}

int SMAC::drop_DATA(Packet *p, const char* why) 
{
	hdr_smac *sh = HDR_SMAC(p);

	if ( (sh->dstAddr == index_) ||
	     (sh->srcAddr == index_) ||
	     ((u_int32_t)sh->dstAddr == MAC_BROADCAST)) {
		drop(p, why);
		return 1;
	}
	return 0;
}

int SMAC::drop_SYNC(Packet *p, const char* why) 
{
	drop(p, why);
	return 1;
}

#ifdef JOURNAL_PAPER
void SMAC::checkMySched()
{
        // check if I am the only one on schedTab[0]
        // if yes, should switch and follow the next available schedule
        // happens when an old node switches to a new schedule
        // and when I drop some inactive nodes from neighbor list(updating)
        int i, schedId;
        schedId = 0;
        if (schedTab_[0].numNodes == 1 && numSched_ > 1 && numNeighb_ > 0) {
                for (i = 1; i < SMAC_MAX_NUM_SCHEDULES; i++) {
                        if (schedTab_[i].numNodes > 0) {  // switch to next available schedule
                                //schedTab_[0].counter = schedTab[i].counter;
                                schedTab_[0].numPeriods = 0;
                                schedTab_[0].txSync = 1;
                                schedTab_[0].txData = schedTab_[i].txData;
                                schedTab_[0].syncNode = schedTab_[i].syncNode;
                                schedTab_[0].numNodes = schedTab_[i].numNodes + 1;
                                // delete this schedule
                                schedTab_[i].numNodes = 0;
                                numSched_--;
                                schedId = i;
                                break;
                        }
                }
                if (schedId > 0){
                        schedState_++;
                        // update my neighbor list which relative to this schedId
                        for (i = 0; i < SMAC_MAX_NUM_NEIGHBORS; i++) {
                                if (neighbList_[i].state > 0 )
                                        if (neighbList_[i].schedId == schedId)
                                                neighbList_[i].schedId = 0;
                        }
                }
        }
}
// update_schedTab_neighbList() is executed whenever the transmission is done
void SMAC::update_schedTab_neighbList()
{
        //update schedTab and neighbList if flag is set
        //we should update the schedTab[].numNodes before we call checkMySched()
        //to ensure the next available schedule is correct
        check_schedFlag();
        if (updateNeighbList_ == 1) {
                update_neighbList();
                updateNeighbList_ = 0;
                schedTab_[0].chkSched = 0;  //we already did checkMySched() in update_neighbList()
        } else if (schedTab_[0].chkSched == 1) {
                checkMySched();
                schedTab_[0].chkSched = 0;
        }
}
                                                                                                                                                            
//update_myNeighbList() is executed whenever the UpdateNeighb timer timesout
void SMAC::update_myNeighbList()
{
        //we should update the schedTab[].numNodes before we call checkMySched()
        //to ensure the next available schedule is correct
        check_schedFlag();
        update_neighbList();
        updateNeighbList_ = 0;
        schedTab_[0].chkSched = 0;  //we already did checkMySched() in update_neighbList()
        txRequest_ = 0;
}
                                                                                                                                                            
void SMAC::update_neighbList()
{
        // update neighbor list,
        // if the node is not active (moved away or died) for a certain time,
        // need to drop it from neighbor list
                                                                                                                                                            
        //printf("\nupdate_neighbList:node %d at %.6f \n", index_, Scheduler::instance().clock());
        int i, schedId;
        //dump();
        for (i = 0; i < SMAC_MAX_NUM_NEIGHBORS; i++) {
                if (neighbList_[i].state > 0 ){
                        if (neighbList_[i].active != 1){ // this node is not active recently
                                //printf("node %d lost a neighbor of node %d: ............at %.6f\n", index_, neighbList_[i].nodeId, Scheduler::instance().clock());
                                schedId = neighbList_[i].schedId;
                                schedTab_[schedId].numNodes--;
                                if (schedTab_[schedId].numNodes == 0)
                                        numSched_--;
                                neighbList_[i].state = 0;
                                numNeighb_--;
                        } else
                                //printf("node %d has a neighbor of node %d: ............at %.6f\n", index_, neighbList_[i].nodeId, Scheduler::instance().clock());
                        neighbList_[i].active = 0;
                }
        }
        //printf("#####################################################\n");
                                                                                                                                                            
        // maybe the inactive nodes were dropped from schedTab[0]
        // check if I am the only one on schedTab[0]
        // if yes, I should follow the next available schedule
        checkMySched();
        mhUpdateNeighb_.resched(SMAC_UPDATE_NEIGHB_PERIOD);
}

void SMAC::check_schedFlag()
{
        int i;
        // decrease the numNodes in the old schedule first
        for (i = 1; i < SMAC_MAX_NUM_SCHEDULES; i++) {
                if (schedTab_[i].numNodes > 0 && schedTab_[i].chkSched == 1){
                        schedTab_[i].chkSched = 0;
                        schedTab_[i].numNodes--;
                        if (schedTab_[i].numNodes == 0)
                                numSched_--;
                }
        }
}
#endif

void SMAC::handleRTS(Packet *p) {
	// internal handler for RTS

	struct smac_control_frame *cf = (smac_control_frame *)p->access(hdr_mac::offset_);
  
	if(cf->dstAddr == index_) {
		if((state_ == IDLE || state_ == CR_SENSE) && nav_ == 0) {
			recvAddr_ = cf->srcAddr; // remember sender's addr
#ifdef JOURNAL_PAPER
                        updateNeighNav(cf->duration);
#endif
			if(sendCTS(cf->duration)) {
				state_ = WAIT_DATA;
				lastRxFrag_ = -3; //reset frag no 
			}
		}
	} else { 
		// pkt destined to another node
		// don't go to sleep unless hear first data fragment
		// so I know how long to sleep
		if (state_ == CR_SENSE)
			state_ = IDLE;
#ifdef JOURNAL_PAPER
                updateNav(cf->duration);
                state_ = DATA_SENSE1;
                mhGene_.sched(timeWaitCtrl_);
#else
		updateNav(durCtrlPkt_ + durDataPkt_);
#endif
	}

}

void SMAC::handleCTS(Packet *p) {
	// internal handler for CTS
	struct smac_control_frame *cf = (smac_control_frame *)p->access(hdr_mac::offset_);
	if(cf->dstAddr == index_) { // for me
		if(state_ == WAIT_CTS && cf->srcAddr == sendAddr_) {
			// cancel CTS timer
			mhGene_.cancel();

			if(sendDATA()) {
				state_ = WAIT_ACK;
#ifndef JORNAL_PAPER
				if (!syncFlag_)
					txData_ = 0;
				else
					schedTab_[currSched_].txData = 0;
#endif
			}
		}
	} else { // for others
		updateNav(cf->duration);
#ifdef JOURNAL_PAPER
                if(state_ == DATA_SENSE1 || state_ == DATA_SENSE2) { mhGene_.cancel();}
                if(state_ == IDLE || state_ == CR_SENSE || state_ == DATA_SENSE1 || state_ == DATA_SENSE2)
                        sleep();
#else
		if(state_ == IDLE || state_ == CR_SENSE)
			sleep();
#endif
	}
}

void SMAC::handleDATA(Packet *p) {

	// internal handler for DATA packet
	struct hdr_cmn *ch = HDR_CMN(p);
	struct hdr_smac * sh = HDR_SMAC(p);
 
	if((u_int32_t)sh->dstAddr == MAC_BROADCAST) { // brdcast pkt
		state_ = IDLE;
		// hand pkt over to higher layer
		rxMsgDone(p);
    
	} else if (sh->dstAddr == index_) { // unicast pkt
		if(state_ == WAIT_DATA && sh->srcAddr == recvAddr_) {
			// Should track neighbors' NAV, in case tx extended
			updateNeighNav(sh->duration);
			sendACK(sh->duration);
#ifdef JOURNAL_PAPER
                        if (sh->duration > durCtrlPkt_) { // wait for more frag
                                rxFragDone(p);   //no frag for now
                                state_ = WAIT_DATA;
                        } else {   // no more fragments
                        	state_ = IDLE;
                                rxMsgDone(p);
                        }

#else
      
			//if (sh->duration > durCtrlPkt_) { // wait for more frag
			//rxFragDone(p);   no frag for now
			//state_ = IDLE;
			//} else {   // no more fragments
      
			state_ = IDLE;
			if(lastRxFrag_ != ch->uid()) {
				lastRxFrag_ = ch->uid();
				rxMsgDone(p);
			}
			else {
				printf("Recd duplicate data pkt at %d from %d! free pkt\n",index_,sh->srcAddr);
				Packet::free(p);
				if (!syncFlag_)
					checkToSend();
			}
#endif
		} else if (state_ == IDLE || state_ == CR_SENSE ) {
			printf("got data pkt in %d state XXX %d\n", state_, index_);
			//updateNav(sh->duration + 0.00001);  // incase I have a pkt to send
			sendACK(sh->duration);
			state_ = IDLE;
			if(lastRxFrag_ != ch->uid()) {
				lastRxFrag_ = ch->uid();
				rxMsgDone(p);
			}
			else {
				printf("Recd duplicate data pkt! free pkt\n");
				Packet::free(p);
				if (!syncFlag_)
					checkToSend();
			}
		} else { // some other state
			// not sure we can handle this
			// so drop pkt
			printf("Got data pkt in !WAIT_DATA/!CR_SENSE/!IDLE state(%d) XXX %d\n", state_, index_);
			printf("Dropping data pkt\n");
			Packet::free(p);
		}
	} else { // unicast pkt destined to other node
		updateNav(sh->duration);
		Packet::free(p);
#ifdef JOURNAL_PAPER
                if (state_ == DATA_SENSE2) { mhGene_.cancel();}
                if (state_ == IDLE || state_ == CR_SENSE || state_ == DATA_SENSE2)
                        sleep();
#else
		if (state_ == IDLE || state_ == CR_SENSE)
			sleep();
#endif
	}
}



void SMAC::handleACK(Packet *p) {
	// internal handler for ack
	struct smac_control_frame *cf = (smac_control_frame *)p->access(hdr_mac::offset_);
  
	if (cf->dstAddr == index_) {
		if (state_ == WAIT_ACK && cf->srcAddr == sendAddr_) {
			// cancel ACK timer
			mhGene_.cancel();
#ifdef JOURNAL_PAPER
                        numFrags_--;
                        succFrags_++;
                        if (numFrags_ > 0) { //need to send more frags
                                  state_ = TX_NEXT_FRAG;
                                  txFragDone();
                               } else {
                        state_ = IDLE;
                        txMsgDone();
			}
#else
			Packet::free(dataPkt_);
			dataPkt_ = 0;
			//numFrags_--;
			//succFrags_++;
      
			// if (numFrags_ > 0) { //need to send more frags
			// 	if (neighNav__ < (durDataPkt_ + durCtrlPkt_)) {
			// 	  // used up reserved time, have to stop
			// 	  state_ = IDLE;
			// 	  // txMsgFailed(succFrags_);
			// 	  txMsgDone();
			// 	} else { // continue on next fragment
			// 	  state_ = WAIT_NEXTFRAG;
			// 	  txFragDone(dataPkt_);
			// 	}

			//       } else {
			state_ = IDLE;
			txMsgDone();
			//}
#endif
		}
    
	} else { // destined to another node
		if (cf->duration > 0) {
			updateNav(cf->duration);
			if (state_ == IDLE || state_ == CR_SENSE)
				sleep();
		}
	}
}

#ifdef JOURNAL_PAPER
void SMAC::handleSYNC(Packet *p) 
{

	struct smac_sync_frame *sf = (struct smac_sync_frame *)p->access(hdr_mac::offset_);
        int i, j,nodeId, schedId, flag;
        struct SchedTable tempSched;
        int foundNeighb = 0;
	if (index_ == 5){
        double t = Scheduler::instance().clock();
        //printf("Recvd SYNC (not/f) at %d from %d.....at %.6f\n", index_, sf->srcAddr, t);
	}
	if (numSched_ == 0) { // in choose_sched state
		mhGene_.cancel();
		setMySched(p);
		return;
	}
      	if (numNeighb_ == 0 && globalSchedule_ == 1) {
         // follow this schedule if having no other neighbor and if this schedule has smaller ID
        	if (schedTab_[0].syncNode > sf->syncNode || !sendSYNCFlag_ ) {
         		setMySched(p);
         		return;
        	}
      	}
      	else if (numNeighb_ == 0) { // getting first sync pkt
         // follow this sched as have no other neighbor
         	setMySched(p);

         	return;
      	}
	state_ = IDLE;

      	// check if sender is on my neighbor list
      	nodeId = SMAC_MAX_NUM_NEIGHBORS;
      	schedId = SMAC_MAX_NUM_SCHEDULES;
      	for (i = 0; i < SMAC_MAX_NUM_NEIGHBORS; i++) {
         	if (neighbList_[i].state > 0 && neighbList_[i].nodeId == sf->srcAddr) {
            		nodeId = i;
            		schedId = neighbList_[i].schedId; // a known neighbor
            		break;
         	}
      	}
      	if (nodeId < SMAC_MAX_NUM_NEIGHBORS) {
         	if (neighbList_[nodeId].state == sf->state) {
            		// update the existing schedule
	    		mhCounter_[schedId]->sched(sf->sleepTime);

            		neighbList_[nodeId].active = 1;
            		if (globalSchedule_ == 1 && schedTab_[0].syncNode > sf->syncNode ){
                   		// change state
                   		schedState_++;
				//printf("#############################################################\n");
                		//printf("node %d hears SYNC from node %d and changes schedule from %d to schedule %d : ............at %.6f\n", index_, sf->srcAddr, schedTab_[0].syncNode, sf->syncNode, Scheduler::instance().clock());
				//printf("#############################################################\n");

                     		tempSched.syncNode = schedTab_[schedId].syncNode;
                     		tempSched.txSync = schedTab_[schedId].txSync;  // need send sync
                     		tempSched.txData = schedTab_[schedId].txData;
                     		tempSched.numPeriods = schedTab_[schedId].numPeriods;
                     		tempSched.numNodes = schedTab_[schedId].numNodes ; //
		                tempSched.chkSched = schedTab_[schedId].chkSched;

                   		if (schedTab_[0].numNodes == 1) {
                     			numSched_--;
                   		}
		     		mhCounter_[schedId]->sched(mhCounter_[0]->timeToSleep());
                     		schedTab_[schedId].syncNode = schedTab_[0].syncNode;
                     		schedTab_[schedId].txSync = schedTab_[0].txSync;  // need send sync
                     		schedTab_[schedId].txData = schedTab_[0].txData;
                     		schedTab_[schedId].numPeriods = schedTab_[0].numPeriods;
                     		schedTab_[schedId].numNodes = schedTab_[0].numNodes - 1; // I switch schedule
                     		schedTab_[schedId].chkSched = schedTab_[0].chkSched;

                    		// new schedule is schedule 0 now
		   		mhCounter_[0]->sched(sf->sleepTime);
                   		schedTab_[0].syncNode = sf->syncNode;
                   		schedTab_[0].txSync = 1;  
                   		schedTab_[0].txData = tempSched.txData;
                   		schedTab_[0].numPeriods = 0; 
                   		schedTab_[0].numNodes = tempSched.numNodes + 1; // I are following this sched
                   		schedTab_[0].chkSched = tempSched.chkSched;

                   		// change all the neighbor who was following shedule 0
                   		for (j = 0; j < SMAC_MAX_NUM_NEIGHBORS; j++) {
                       			if (neighbList_[j].schedId == 0) { // found an empty entry
                         			neighbList_[j].schedId = schedId;
                       			}
                       			else if (neighbList_[j].schedId == schedId) { // found an empty entry
                         			neighbList_[j].schedId = 0;
                       			}
                    		}
                 	}
            	return;
         	} else {

                	// decrement number of nodes on old schedule

            		if (schedTab_[schedId].numNodes ==1 && txRequest_ == 1) {
                		//set flag to decrement numNodes after tx pkt is done
               			schedTab_[schedId].chkSched = 1;
            		}
            		else 
			{
               			schedTab_[schedId].numNodes--; 
               			if (schedTab_[schedId].numNodes == 0){
                  			numSched_--;
               			}
       			}

		}
	}

      	// now it's either a new node or an old node switching to a new schedule
      	// it is also possible that a node switches to an existing schedule
      	// check if its schedule is a known one to me
      	schedId = SMAC_MAX_NUM_SCHEDULES;
      	for (i = 0; i < SMAC_MAX_NUM_SCHEDULES; i++) {
         	if (schedTab_[i].numNodes > 0) {
	    
	    		double t = mhCounter_[i]->timeToSleep();
	    		double st = sf->sleepTime;
	    		double timeDiff = st - t;
            		if ( timeDiff > -GUARDTIME && timeDiff < GUARDTIME) {
				mhCounter_[i]->sched(sf->sleepTime);

               			schedTab_[i].numNodes++; // it will follow this schedule
               			schedId = i;
             		 	break;
            		} 
         	}
      	}

      	if (schedId == SMAC_MAX_NUM_SCHEDULES) {  // unknow schedule
        	flag =1;
         	// add an entry to the schedule table
         	if (numSched_ < SMAC_MAX_NUM_SCHEDULES){
            		for (i = 0; i < SMAC_MAX_NUM_SCHEDULES; i++) {
              			if (schedTab_[i].numNodes == 0) { // found an empty entry
                 		// check if I need to switch
  				if (globalSchedule_ == 1 && schedTab_[0].syncNode > sf->syncNode ){
        		        	// change state
                   			schedState_++;
					//printf("#############################################################\n");
                			//printf("node %d hears SYNC from node %d and changes schedule from %d to schedule %d : ............at %.6f\n", index_, sf->srcAddr, schedTab_[0].syncNode, sf->syncNode, Scheduler::instance().clock());
                			//printf("#############################################################\n");

                   			if (schedTab_[0].numNodes >= 2) { // need to move old schedule 0 to schedule i
		     				mhCounter_[i]->sched(mhCounter_[0]->timeToSleep());
                     				schedTab_[i].syncNode = schedTab_[0].syncNode;
                     				schedTab_[i].txSync = schedTab_[0].txSync;  // need send sync
                     				schedTab_[i].txData = schedTab_[0].txData;
                     				schedTab_[i].numPeriods = schedTab_[0].numPeriods;
                     				schedTab_[i].numNodes = schedTab_[0].numNodes - 1; // I switch schedule
                     				schedTab_[i].chkSched = schedTab_[0].chkSched;
                     				numSched_++;  // increment number of schedules
                     				// change all the neighbor who was following shedule 0
                     				for (j = 0; j < SMAC_MAX_NUM_NEIGHBORS; j++) {
                       					if (neighbList_[j].schedId == 0) { // found an empty entry
                         					neighbList_[j].schedId = i;
                       					}
                     				}
                   			}
                   	 		// new schedule is schedule 0 now
		   			mhCounter_[0]->sched(sf->sleepTime);
                   			schedTab_[0].syncNode = sf->syncNode;
                   			schedTab_[0].txSync = 1;  // need send sync
                   			schedTab_[0].txData = 0;
		   			schedTab_[0].numPeriods = 0;
                   			schedTab_[0].numNodes = 2; // 1st node + I are following this sched
                   			schedTab_[0].chkSched = 0;

                   			schedId = 0;
                 		}
                 		else { // fill new schedule in schedule i

         	   			mhCounter_[i]->sched(sf->sleepTime);
                   			schedTab_[i].syncNode = sf->syncNode;
                   			schedTab_[i].txSync = 1;  // need send sync
                   			schedTab_[i].txData = 0;
                   			schedTab_[i].numPeriods = 0;
                   			schedTab_[i].numNodes = 1; // 1st node following this sched
                   			schedTab_[i].chkSched = 0;
                   			schedId = i;
                   			numSched_++;  // increment number of schedules
                 		}
                 		break;
              			}
            		}
		}
	}

      	if (nodeId == SMAC_MAX_NUM_NEIGHBORS) {  // a new node
         	// didn't find an empty entry in schedule table, just drop the new node
         	if (schedId == SMAC_MAX_NUM_SCHEDULES) return;
         	// add it to my neighbor list
         	if (numNeighb_ < SMAC_MAX_NUM_NEIGHBORS){
            	for (i = 0; i < SMAC_MAX_NUM_NEIGHBORS; i++) {
              		if (neighbList_[i].state == 0) { // found an empty entry
                 		neighbList_[i].state = sf->state;
                 		neighbList_[i].nodeId = sf->srcAddr;
                 		neighbList_[i].schedId = schedId;
                 		neighbList_[i].active = 1;
                 		numNeighb_++;  // increment number of neighbors
                 		return;
              		}
            	}
         }
         // didn't find an empty entry in neighb list, just drop the new node
	schedTab_[schedId].numNodes--;
        if (schedTab_[schedId].numNodes == 0)
        	numSched_--;
      	} else if (flag == 1) {  // old node switches to a new schedule
        	// didn't find an empty entry in schedule table, delete the old node
        	if (schedId == SMAC_MAX_NUM_SCHEDULES) {
            		neighbList_[nodeId].state = 0;
            		numNeighb_--;  // decrement number of neighbors
         	} else {
            		neighbList_[nodeId].state = sf->state;
            		neighbList_[nodeId].schedId = schedId;
            		neighbList_[nodeId].active = 1;
         	}

         	// maybe the old node switches from schedTab_[0]
         	// check if I am the only one on schedTab_[0] now
         	// if yes, I should follow the next available schedule
         	if (txRequest_ == 0) {
            		checkMySched();
         	} else {
         		// set flag to call checkMySched() when txRequest_ becomes 0
            		schedTab_[0].chkSched = 1;
         	}
      	} else {  // old node switches to old schedule
            	neighbList_[nodeId].state = sf->state;
            	neighbList_[nodeId].schedId = schedId;
            	neighbList_[nodeId].active = 1;
  		if (globalSchedule_ == 1 && schedTab_[0].syncNode > sf->syncNode ){
			//printf("#############################################################\n");
                	//printf("node %d hears SYNC from node %d and changes schedule from %d to schedule %d : ............at %.6f\n", index_, sf->srcAddr, schedTab_[0].syncNode, sf->syncNode, Scheduler::instance().clock());
                	//printf("#############################################################\n");

                   	// change state
                   	schedState_++;
                     	tempSched.syncNode = schedTab_[schedId].syncNode;
                     	tempSched.txSync = schedTab_[schedId].txSync;  // need send sync
                     	tempSched.txData = schedTab_[schedId].txData;
                     	tempSched.numPeriods = schedTab_[schedId].numPeriods;
                     	tempSched.numNodes = schedTab_[schedId].numNodes ; //
                     	tempSched.chkSched = schedTab_[schedId].chkSched;

                   	if (schedTab_[0].numNodes == 1) {
                     		numSched_--;
                   	}
		     	mhCounter_[schedId]->sched(mhCounter_[0]->timeToSleep());
                     	schedTab_[schedId].syncNode = schedTab_[0].syncNode;
                     	schedTab_[schedId].txSync = schedTab_[0].txSync;  // need send sync
                     	schedTab_[schedId].txData = schedTab_[0].txData;
                     	schedTab_[schedId].numPeriods = schedTab_[0].numPeriods;
                     	schedTab_[schedId].numNodes = schedTab_[0].numNodes - 1; // I switch schedule
                     	schedTab_[schedId].chkSched = schedTab_[0].chkSched;

                    	/// new schedule is schedule 0 now
                    	mhCounter_[0]->sched(sf->sleepTime);

                   	schedTab_[0].syncNode = sf->syncNode;
                   	schedTab_[0].txSync = 1; 
                   	schedTab_[0].txData = tempSched.txData;
                   	schedTab_[0].numPeriods = 0;
                   	schedTab_[0].numNodes = tempSched.numNodes + 1; // I are following this sched
                   	schedTab_[0].chkSched = tempSched.chkSched;

                  	// change all the neighbor who was following shedule 0
                   	for (j = 0; j < SMAC_MAX_NUM_NEIGHBORS; j++) {
                       		if (neighbList_[j].schedId == 0) { // found an empty entry
                         		neighbList_[j].schedId = schedId;
                       		}
                       		else if (neighbList_[j].schedId == schedId) { // found an empty entry
                         		neighbList_[j].schedId = 0;
                       		}
                    	}

         	}
		return;
	}

}
#else

void SMAC::handleSYNC(Packet *p) 
{
//printf("node: %d ..............data sent............\n",index_);
	if ( selfConfigFlag_ == 1) {
		if(numSched_ == 0) { // in choose_sched state
			mhGene_.cancel();
			//double t = Scheduler::instance().clock();
			//struct smac_sync_frame *sf = (struct smac_sync_frame *)p->access(hdr_mac::offset_);
			//printf("Recvd SYNC (follow) at %d from %d.....at %.6f\n", index_, sf->srcAddr, t);
			setMySched(p);
			return;
		}
		if (numNeighb_ == 0) { // getting first sync pkt
			// follow this sched as have no other neighbor
		        //double t = Scheduler::instance().clock();
			//struct smac_sync_frame *sf = (struct smac_sync_frame *)p->access(hdr_mac::offset_);
			//printf("Recvd SYNC (follow) at %d from %d.....at %.6f\n", index_, sf->srcAddr, t);
		        setMySched(p);
			return;
		}
	}
	state_ = IDLE;
	// check if sender is on my neighbor list
	struct smac_sync_frame *sf = (struct smac_sync_frame *)p->access(hdr_mac::offset_);
	int i, j;
	int foundNeighb = 0;
	int schedId = SMAC_MAX_NUM_SCHEDULES;
	//double t = Scheduler::instance().clock();
	//printf("Recvd SYNC (not/f) at %d from %d.....at %.6f\n", index_, sf->srcAddr, t);
  
	for(i = 0; i < numNeighb_; i++) {
		if (neighbList_[i].nodeId == sf->srcAddr) {
			foundNeighb = 1;
			schedId = neighbList_[i].schedId;  // a known neighbor
			mhCounter_[schedId]->sched(sf->sleepTime);
			break;
		}
		if (neighbList_[i].nodeId == sf->syncNode)
			// // found its synchronizer, remember it schedule id
			schedId = neighbList_[i].schedId;
	}
	if (!foundNeighb) { // unknown node, add it onto neighbor list
		neighbList_[numNeighb_].nodeId = sf->srcAddr;
		if (schedId < SMAC_MAX_NUM_SCHEDULES) {
			// found its synchronizer
			neighbList_[numNeighb_].schedId = schedId;
		} else if (sf->syncNode == index_) { // this node follows my schedule
			neighbList_[numNeighb_].schedId = 0;
		} else { // its synchronizer is unknown
			// check if its schedule equals to an existing one
			int foundSched = 0;
			for (j = 0; j < numSched_; j++) {
				double t = mhCounter_[j]->timeToSleep();
				double st = sf->sleepTime; 
				if (t == st || (t + CLKTICK2SEC(1)) == st || t == (st + CLKTICK2SEC(1))) {
					neighbList_[numNeighb_].schedId = j;
					foundSched = 1;
					break;
				}
			}
			if (!foundSched) { // this is unknown schedule
				schedTab_[numSched_].txSync = 1;
				schedTab_[numSched_].txData = 0;
				schedTab_[numSched_].numPeriods = 0;
				neighbList_[numNeighb_].schedId = numSched_;
				mhCounter_[numSched_]->sched(sf->sleepTime);
				numSched_++;
			}
		}
		numNeighb_++;  // increment number of neighbors
	}
}

#endif
void SMAC::rxMsgDone(Packet *p) {
	// no more fragments
	// defragment all pkts and send them up
	// fragmentation/de-frag to be implemented
  
	if (p)
		uptarget_->recv(p, (Handler*)0);
  
	if (!syncFlag_)
		// check if any pkt waiting to get tx'ed
		checkToSend();
#ifdef JOURNAL_PAPER
	//node tries to go to sleep after receiving the message
	//we temperarily disable sleep() here, because in the testcases where ARP messages exist, more than one message need to be transmitted in one round
        else {
//                if( mhCounter_[0]->value_ == sleepTime_ ) 
//                        sleep();
        }
#endif
}

#ifdef JOURNAL_PAPER
void SMAC::rxFragDone(Packet *p) {
//  more fragments to come
}
#endif

//void SMAC::rxFragDone(Packet *p) {
// more fragments to come
//}

// mac transmission functions

void SMAC::transmit(Packet *p) {
  
	radioState_ = RADIO_TX;
	tx_active_ = 1;
	pktTx_ = p;

	double transTime = txtime(p);
	hdr_cmn *ch = hdr_cmn::access(p);
	ch->txtime() = transTime;
//	printf("%d MAC sending at %f\n",index_,NOW);	
	downtarget_->recv(p->copy(), this);
	//Scheduler::instance().schedule(downtarget_, p, 0.000001);
	mhSend_.sched(txtime(p));

}

bool SMAC::chkRadio() {
	// check radiostate
	if (radioState_ == RADIO_IDLE || radioState_ == RADIO_SLP)
		return (1);

	return (0); // phy interface is ready to tx
}


int SMAC::startBcast()
{
	// broadcast data directly; don't use RTS/CTS

	hdr_smac *mh = HDR_SMAC(dataPkt_);
  
	mh->duration = 0;

	if(chkRadio()) {
		transmit(dataPkt_);
		return 1;
	}
  
	return 0;
}


int SMAC::startUcast()
{
printf("node: %d ..............data sent Uni............\n",index_);
	// start unicast data; send RTS first
	hdr_smac *mh = HDR_SMAC(dataPkt_);
  
	sendAddr_ = mh->dstAddr;
	numRetry_ = 0;
	//succFrags_ = 0;
#ifdef JOURNAL_PAPER
	succFrags_ = 0;
#endif
	numExtend_ = 0; 
	if(sendRTS()) {
		state_ = WAIT_CTS;
		return 1;
	}
  
	return 0;
}


void  SMAC::txMsgDone() 
{
#ifdef JOURNAL_PAPER
        // update schedTab and neighbList if flags are set when txRequest_=1
        update_schedTab_neighbList();
        txRequest_ = 0;
#endif
	if (!syncFlag_) {
#ifdef JOURNAL_PAPER
                txData_ = 0;
#endif
		// check if any data is waiting to get tx'ed
		if(checkToSend())
			return;
		else if (callback_) { // signal upper layer
			Handler *h = callback_;
			callback_ = 0;
			h->handle((Event*) 0);
		}
	} else {
#ifdef JOURNAL_PAPER
                schedTab_[dataSched_].txData = 0;
#endif

		if (callback_) { // signal upper layer
			Handler *h = callback_;
			callback_ = 0;
			h->handle((Event*) 0);
		}
#ifdef JOURNAL_PAPER
		//node tries to go to sleep after transmission is done (both unicast and broadcast)
                if( mhCounter_[0]->value_ == sleepTime_ )
                        sleep();
#endif
	}
  
}

// void SMAC::txFragDone() 
// {
//   // send next fragment

// }

#ifdef JOURNAL_PAPER
void SMAC::txFragDone()
{
   // send next fragment
        txNextFrag(&dataPkt_);
}
                                                                                                                                                            
bool SMAC::txNextFrag(void* data)
{
      // Send subsequent fragments
                                                                                                                                                            
        if (state_ != TX_NEXT_FRAG || data == 0) return 0;
//      dataPkt = (MACHeader*)data;
      // fill in MAC header fields except duration
//      dataPkt->type = DATA_PKT;  // data pkt
//      dataPkt->toAddr = sendAddr;
//      dataPkt->fromAddr = TOS_LOCAL_ADDRESS;
//      dataPkt->fragNo = txFragCount;
//      if (neighbNav >= (SIFS + durDataPkt + timeWaitCtrl)) {
         // schedule to send this fragment, no need for carrier sense
//         state = TX_PKT;
        if(sendDATA()) {
                state_ = WAIT_ACK;
                if (!syncFlag_)
                        txData_ = 0;
                else
                        schedTab_[dataSched_].txData = 0;
                        //schedTab_[currSched_].txData = 0;
        }
                                                                                                                                                            
//      } // else will retry when neighbNav timeout
        return 1;
}
#endif

bool SMAC::sendMsg(Packet *pkt, Handler *h) {
	struct hdr_smac *mh = HDR_SMAC(pkt);
#ifdef JOURNAL_PAPER
        struct hdr_cmn *ch = HDR_CMN(pkt);
#endif
	callback_ = h;
	if ((u_int32_t)mh->dstAddr == MAC_BROADCAST) {
		return (bcastMsg(pkt));
	} else {
#ifdef JOURNAL_PAPER
                //printf("message length: %d\n",ch->size_);
                // need upper level support here
                int fragNum = ch->size_ / SIZEOF_SMAC_DATAPKT ;
                if (fragNum == 0) fragNum = 1;
                //printf("message length:%d\n",fragNum);
                return unicastMsg(fragNum, pkt);     // for now no fragmentation
#else
		return (unicastMsg(1, pkt));     // for now no fragmentation
#endif
		// fragmentation limit is 40 bytes per pkt.
		// max_msg_size is tentatively 1000 bytes; weiye will confirm this
	}
}


bool SMAC::bcastMsg(Packet *p) {
	//if (dataPkt_ != 0 || p == 0) 
	//return 0;
	assert(p);
  
	//if (state_ != IDLE && state_ != SLEEP && state_!= WAIT_DATA)
	//return 0;

	//char * mh = (char *)p->access(hdr_mac::offset_);
	//int dst = hdr_dst(mh);
	//int src = hdr_src(mh);
  
	struct hdr_smac *sh = HDR_SMAC(p);
  
	sh->type = DATA_PKT;
	sh->length = SIZEOF_SMAC_DATAPKT;
	//sh->srcAddr = src;
	//sh->dstAddr = dst;
	dataPkt_ = p;
#ifdef JOURNAL_PAPER
        // Don't accept Tx request if I have already accepted a request
        if (txRequest_ == 0) {
                txRequest_ = 1;
        }
        else {
                return 0;
        }
                                                                                                                                                            
        for (int i = 0; i < SMAC_MAX_NUM_SCHEDULES; i++) {
                 if (schedTab_[i].numNodes > 0) {
                        //printf("txData[%d] = 1: ............node %d at %.6f\n", i, index_, Scheduler::instance().clock());
                        schedTab_[i].txData = 1;
         }
      }
#else
	for(int i=0; i < numSched_; i++) {
		schedTab_[i].txData = 1;
	}
#endif
	if (!syncFlag_) {
		txData_ = 1;
		// check if can send now
		if (checkToSend())
			return 1;
		else 
			return 0;
  
	} else {
		numBcast_ = numSched_;
		return 1;
	}
}

bool SMAC::unicastMsg(int numfrags, Packet *p) {

	//  if (dataPkt != 0 || p == 0)
	//return 0;

	assert(p);

	//if (state_ != IDLE && state_ != SLEEP && state_!= WAIT_DATA)
	//return 0;

  
	char * mh = (char *)p->access(hdr_mac::offset_);
	int dst = hdr_dst(mh);
	int src = hdr_src(mh);

	// search for schedule of dest node
	struct hdr_smac *sh = HDR_SMAC(p);
	//int dst = sh->dstAddr;

	if (syncFlag_) {
		int found = 0;
		for (int i=0; i < numNeighb_; i++) {
			if (neighbList_[i].nodeId == dst) {
				found = 1;
#ifdef JOURNAL_PAPER
                                sendAddr = UNICAST_ADDR;
                                dataSched_ = neighbList_[i].schedId;
#endif
				schedTab_[neighbList_[i].schedId].txData = 1;
				break;
			}
		}
		if (found == 0) {
			printf("Neighbor unknown; cannot send pkt\n");
			return 0;  // unknown neighbor
		}
	}
#ifdef JOURNAL_PAPER
        // Don't accept Tx request if I have already accepted a request
        if (txRequest_ == 0) {
                txRequest_ = 1;
        }
        else {
                return 0;
        }
        numFrags_ = numfrags; 
#endif
	sh->type = DATA_PKT;
	sh->length = SIZEOF_SMAC_DATAPKT;
	sh->dstAddr = dst;
	sh->srcAddr = src;
	//numFrags_ = numfrags;
	dataPkt_ = p;

	if (!syncFlag_) {
		txData_ = 1;
    
		// check if can send now
		if (checkToSend())
			return 1;
		else
			return 0;
    
	} else 
		return 1;
}


bool SMAC::sendRTS() {

//printf("node: %d ..............data sent............\n",index_);
	// construct RTS pkt
	Packet *p = Packet::alloc();
	struct smac_control_frame *cf = (struct smac_control_frame *)p->access(hdr_mac::offset_);
	struct hdr_cmn *ch = HDR_CMN(p);

	ch->uid() = 0;
	ch->ptype() = PT_SMAC;
	ch->size() = SIZEOF_SMAC_CTRLPKT;
	ch->iface() = UNKN_IFACE.value();
	ch->direction() = hdr_cmn::DOWN;
	ch->error() = 0;	/* pkt not corrupt to start with */
  

	bzero(cf, MAC_HDR_LEN);
  
	cf->length = SIZEOF_SMAC_CTRLPKT;
	cf->type = RTS_PKT;
  
	cf->srcAddr = index_;  // mac_id
	cf->dstAddr = sendAddr_;

	// reserved time for CTS + all fragments + all acks
	//cf->duration = (numFrags_ + 1) * durCtrlPkt_ + numFrags_ * durDataPkt_;
#ifdef JOURNAL_PAPER
	cf->duration = (numFrags_ + 1) * durCtrlPkt_ + numFrags_ * durDataPkt_;
#else
	cf->duration = (2 * durCtrlPkt_ + durDataPkt_ + 0.001 ); 
#endif
	cf->crc = 0;
 
	// send RTS
	if (chkRadio()) {
		transmit(p);
		return 1;
    
	} else 
		return 0;

}


bool SMAC::sendCTS(double duration) {
  
	// construct CTS
	Packet *p = Packet::alloc();
	struct smac_control_frame *cf = (struct smac_control_frame *)p->access(hdr_mac::offset_);
	struct hdr_cmn *ch = HDR_CMN(p);

	ch->uid() = 0;
	ch->ptype() = PT_SMAC;
	ch->size() = SIZEOF_SMAC_CTRLPKT;
	ch->iface() = UNKN_IFACE.value();
	ch->direction() = hdr_cmn::DOWN;
	ch->error() = 0;	/* pkt not corrupt to start with */

	bzero(cf, MAC_HDR_LEN);
  
	cf->length = SIZEOF_SMAC_CTRLPKT;
	cf->type = CTS_PKT;
  
	cf->srcAddr = index_;
	cf->dstAddr = recvAddr_;

	// input duration is the duration field from received RTS pkt  
	cf->duration = duration - durCtrlPkt_ ;  
	cf->crc = 0;
	// send CTS
	if (chkRadio()) {
		transmit(p);
		return 1;

	} else
		return 0;
}


bool SMAC::sendDATA() {

	// assuming data pkt is already constructed
	struct hdr_smac * sh = HDR_SMAC(dataPkt_);
  
	//sh->duration = numFrags_ * durCtrlPkt_ + (numFrags_ - 1) * durDataPkt_;
#ifdef JOURNAL_PAPER
	sh->duration = numFrags_ * durCtrlPkt_ + (numFrags_ - 1) * durDataPkt_;
#else
	sh->duration =  durCtrlPkt_;
#endif  
	// send DATA
	if (chkRadio()) {
		transmit(dataPkt_);
		
		return 1;

	} else 
		return 0;

}


bool SMAC::sendACK(double duration) {
	// construct ACK pkt
	Packet *p = Packet::alloc();
	struct smac_control_frame *cf = (struct smac_control_frame *)p->access(hdr_mac::offset_);
	struct hdr_cmn *ch = HDR_CMN(p);

	ch->uid() = 0;
	ch->ptype() = PT_SMAC;
	ch->size() = SIZEOF_SMAC_CTRLPKT;
	ch->iface() = UNKN_IFACE.value();
	ch->direction() = hdr_cmn::DOWN;
	ch->error() = 0;	/* pkt not corrupt to start with */
  
	bzero(cf, MAC_HDR_LEN);
  
  cf->length = SIZEOF_SMAC_CTRLPKT;
  cf->type = ACK_PKT;
  
  cf->srcAddr = index_;
  cf->dstAddr = recvAddr_;
  
  // input duration is the duration field from recvd data pkt
  // stick to neighbNav -- should update it when rx data packet
  cf->duration = duration - durCtrlPkt_;
  //cf->duration = mhNeighNav_.timeToExpire() - durCtrlPkt_;
  
  // send ACK
  if (chkRadio()) {
    transmit(p);
    return 1;
  } else
    return 0;
}

bool SMAC::sendSYNC()
{
  // construct and send SYNC pkt
  Packet *p = Packet::alloc();
  struct smac_sync_frame *cf = (struct smac_sync_frame *)p->access(hdr_mac::offset_);
  struct hdr_cmn *ch = HDR_CMN(p);

  ch->uid() = 0;
  ch->ptype() = PT_SMAC;
  ch->size() = SIZEOF_SMAC_SYNCPKT;
  ch->iface() = UNKN_IFACE.value();
  ch->direction() = hdr_cmn::DOWN;
  ch->error() = 0;	/* pkt not corrupt to start with */
  
  cf->length = SIZEOF_SMAC_SYNCPKT;
  cf->type = SYNC_PKT;
  
  cf->srcAddr = index_;
#ifdef JOURNAL_PAPER
  cf->syncNode = schedTab_[0].syncNode;
  cf->state = schedState_;
#else
 cf->syncNode = mySyncNode_;
#endif
  // shld change SYNCPKTTIME to match with the configures durSyncPkt_
  cf->sleepTime = mhCounter_[0]->timeToSleep() - CLKTICK2SEC(SYNCPKTTIME);
  if (cf->sleepTime < 0)
    cf->sleepTime += CLKTICK2SEC(cycleTime_);
  
  // send SYNC
  if (chkRadio()) {
//	if(index_==0)
//	printf("%d Sent SYNC at %.6f\n", index_,Scheduler::instance().clock());

    transmit(p);
    //double t = Scheduler::instance().clock();
    //printf("Sent SYNC from %d.....at %.6f\n", cf->srcAddr, t);
    return 1;
    
  } else 
    return 0;
}


void SMAC::sentRTS(Packet *p)
{
  // just sent RTS, set timer for CTS timeout
  mhGene_.sched(timeWaitCtrl_);
  Packet::free(p);
  
}

void SMAC::sentCTS(Packet *p)
{
  // just sent CTS, track my neighbors' NAV
  // they update NAV and go to sleep after recv CTS
  // no data timeout, just use neighbors' NAV
  // since they went to sleep, just wait data for the entire time

  struct smac_control_frame *cf = (struct smac_control_frame *)p->access(hdr_mac::offset_);
  
  updateNeighNav(cf->duration);
  Packet::free(p);
}

void SMAC::sentDATA(Packet *p)
{
  struct hdr_smac *mh = HDR_SMAC(p);
  
  if (howToSend_ == BCASTDATA) { // if data was brdcast
    state_ = IDLE;

    if (!syncFlag_) {
      txData_ = 0;
      dataPkt_ = 0;
      Packet::free(p);
    
      // signal upper layer
      txMsgDone(); 
    
    } else {
#ifdef JOURNAL_PAPER
      schedTab_[dataSched_].txData = 0;
#else
      schedTab_[currSched_].txData = 0;
#endif
      numBcast_--;
      if (numBcast_ == 0) {
	dataPkt_ = 0;
	Packet::free(p);
#ifdef JOURNAL_PAPER
        txRequest_ = 0;
#endif	
	// signal upper layer
	txMsgDone(); 
      }
#ifdef JOURNAL_PAPER
	//when broadcast data is done for one schedule, sender needs to sleep
      	if( mhCounter_[0]->value_ == sleepTime_ )
        	 sleep();
#endif
    }
    
  } else {
    
    // unicast is done; track my neighbors' NAV
    // they update NAV and go to sleep after recv first data fragment
#ifdef JOURNAL_PAPER
    sendAddr = -1;
    txRequest_ = 0;
#endif
    updateNeighNav(mh->duration);
      
    //waiting for ACK, set timer for ACK timeout
    mhGene_.sched(timeWaitCtrl_);

  }
}

void SMAC::sentACK(Packet *p)
{
  struct smac_control_frame *cf = (struct smac_control_frame *)p->access(hdr_mac::offset_);
  
  updateNeighNav(cf->duration);
  Packet::free(p);
}

void SMAC::sentSYNC(Packet *p)
{
#ifdef JOURNAL_PAPER
  schedTab_[syncSched_].txSync = 0;
  schedTab_[syncSched_].numPeriods = SYNCPERIOD;
#else
  schedTab_[currSched_].txSync = 0;
  schedTab_[currSched_].numPeriods = SYNCPERIOD;
#endif
  Packet::free(p);

}

void SMAC::sleep() 
{
  // go to sleep, turn off radio
  state_ = SLEEP;
  radioState_ = RADIO_SLP;
#ifdef JOURNAL_PAPER
  //printf("SLEEP: ............node %d at %.6f\n", index_, Scheduler::instance().clock());
#endif
  // printf("SLEEP: ............node %d at %.6f\n", index_, Scheduler::instance().clock());
//printf("%d SMAC SLEEP: at %.6f\n", index_,Scheduler::instance().clock());


// set node state
	Phy *p;
	p=netif_;			
	((WirelessPhy *)p)->node_sleep();
//	printf("\nnetif\n %d", ((WirelessPhy *)p)->testfun(34));
//

}

void SMAC::wakeup()
{
  //wakeup from sleep. turn on radio
  state_ = IDLE;
  
  // since radio can start to recv while in sleep
  // it might be in RX state
  // and eventually the pkt will not be recvd if in sleep state 
  // so careful not to change state of radio unless it is really sleeping
  if (radioState_ == RADIO_SLP)
    radioState_ = RADIO_IDLE;
#ifdef JOURNAL_PAPER
  //printf("WAKEUP: ............node %d at %.6f\n", index_, Scheduler::instance().clock());
#endif
//   printf("WAKEUP: ............node %d at %.6f\n", index_, Scheduler::instance().clock());

	Phy *p;
	p=netif_;			
	((WirelessPhy *)p)->node_wakeup();


//printf("WAKEUP: ............node %d at %.6f\n", index_, Scheduler::instance().clock());
}

void SMAC::updateNav(double d ) {
  double now = Scheduler::instance().clock();
  // already in sec
  // double d = duration * 1.0e-6; // convert to sec

  if ((now + d) > nav_) {
    nav_ = now + d;
    
    mhNav_.resched(d);
    
  }
}
	

void SMAC::updateNeighNav(double d ) {
  double now = Scheduler::instance().clock();
  //double d = duration * 1.0e-6; // convert to sec

  if ((now + d) > neighNav_) {
    neighNav_ = now + d;

    mhNeighNav_.resched(d);
  
  }
}

double SMAC::txtime(Packet *p)
{
  struct hdr_smac *sh = HDR_SMAC(p);

  switch(sh->type) {
  
  case DATA_PKT:
    return durDataPkt_;
    
  case RTS_PKT:
  case CTS_PKT:
  case ACK_PKT:
    return durCtrlPkt_;
  case SYNC_PKT:
    return CLKTICK2SEC(SYNCPKTTIME);
  default:
    fprintf(stderr, "invalid smac pkt type %d\n", sh->type);
    exit(1);
  }
  
}
#ifdef JOURNAL_PAPER
void SMAC::dump(){
        int i;
        for (i = 0; i < 5; i++) {
                                                                                                                                                            
        printf(" neighbor: %d schedule: %d state: %d active: %d \n", neighbList_[i].nodeId, neighbList_[i].schedId, neighbList_[i].state, neighbList_[i].active);
        }
                                                                                                                                                            
         for (i = 0; i < 4; i++) {
         printf(" schedule: %d numNodes: %d \n",schedTab_[i].syncNode, schedTab_[i].numNodes);
         }
}
#endif


syntax highlighted by Code2HTML, v. 0.9.1