/* * 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