📄 smac.cc
字号:
// Copyright (c) 2000 by the University of Southern California// All rights reserved.//// Permission to use, copy, modify, and distribute this software and its// documentation in source and binary forms for non-commercial purposes// and without fee is hereby granted, provided that the above copyright// notice appear in all copies and that both the copyright notice and// this permission notice appear in supporting documentation. and that// any documentation, advertising materials, and other materials related// to such distribution and use acknowledge that the software was// developed by the University of Southern California, Information// Sciences Institute. The name of the University may not be used to// endorse or promote products derived from this software without// specific prior written permission.//// THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about// the suitability of this software for any purpose. THIS SOFTWARE IS// PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,// INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.//// Other copyrights might apply to parts of this software and are so// noted when applicable.// 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 "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 expirationint SmacTimer::busy(){ if (status_ != TIMER_PENDING) return 0; else return 1;}#ifdef JOURNAL_PAPERvoid SmacUpdateNeighbTimer::expire(Event *e) { a_->handleUpdateNeighbTimer();} void SmacAdaptiveListenTimer::expire(Event *e) { a_->handleAdaptiveListenTimer();}#endifvoid 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 timervoid 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_PAPERSMAC::SMAC() : Mac(), mhUpdateNeighb_(this),mhNav_(this), mhNeighNav_(this), mhSend_(this), mhRecv_(this), mhGene_(this), mhCS_(this), mhAdap_(this), syncFlag_(0) { int i;#elseSMAC::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());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -