mac-tdma.cc

Go to the documentation of this file.
00001 // -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*-
00002 
00003 /*
00004  * mac-tdma.cc
00005  * Copyright (C) 1999 by the University of Southern California
00006  * $Id: mac-tdma.cc,v 1.15 2005/09/18 23:33:33 tomh Exp $
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License,
00010  * version 2, as published by the Free Software Foundation.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License along
00018  * with this program; if not, write to the Free Software Foundation, Inc.,
00019  * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
00020  *
00021  *
00022  * The copyright of this module includes the following
00023  * linking-with-specific-other-licenses addition:
00024  *
00025  * In addition, as a special exception, the copyright holders of
00026  * this module give you permission to combine (via static or
00027  * dynamic linking) this module with free software programs or
00028  * libraries that are released under the GNU LGPL and with code
00029  * included in the standard release of ns-2 under the Apache 2.0
00030  * license or under otherwise-compatible licenses with advertising
00031  * requirements (or modified versions of such code, with unchanged
00032  * license).  You may copy and distribute such a system following the
00033  * terms of the GNU GPL for this module and the licenses of the
00034  * other code concerned, provided that you include the source code of
00035  * that other code when and as the GNU GPL requires distribution of
00036  * source code.
00037  *
00038  * Note that people who make modified versions of this module
00039  * are not obligated to grant this special exception for their
00040  * modified versions; it is their choice whether to do so.  The GNU
00041  * General Public License gives permission to release a modified
00042  * version without this exception; this exception also makes it
00043  * possible to release a modified version which carries forward this
00044  * exception.
00045  *
00046  */
00047 
00048 //
00049 // $Header: /nfs/jade/vint/CVSROOT/ns-2/mac/mac-tdma.cc,v 1.15 2005/09/18 23:33:33 tomh Exp $
00050 //
00051 // mac-tdma.cc
00052 // by Xuan Chen (xuanc@isi.edu), ISI/USC
00053 //
00054 // Preamble TDMA MAC layer for single hop.
00055 // Centralized slot assignment computing.
00056 
00057 
00058 #include "delay.h"
00059 #include "connector.h"
00060 #include "packet.h"
00061 #include "random.h"
00062 
00063 // #define DEBUG
00064 
00065 //#include <debug.h>
00066 
00067 #include "arp.h"
00068 #include "ll.h"
00069 #include "mac.h"
00070 #include "mac-tdma.h"
00071 #include "wireless-phy.h"
00072 #include "cmu-trace.h"
00073 
00074 
00075 #define SET_RX_STATE(x)         \
00076 {                   \
00077     rx_state_ = (x);            \
00078 }
00079 
00080 #define SET_TX_STATE(x)             \
00081 {                       \
00082     tx_state_ = (x);                \
00083 }
00084 
00085 /* Phy specs from 802.11 */
00086 static PHY_MIB PMIB = {
00087     DSSS_CWMin, DSSS_CWMax, DSSS_SlotTime, DSSS_CCATime,
00088     DSSS_RxTxTurnaroundTime, DSSS_SIFSTime, DSSS_PreambleLength,
00089     DSSS_PLCPHeaderLength
00090 };  
00091 
00092 /* Timers */
00093 void MacTdmaTimer::start(Packet *p, double time)
00094 {
00095     Scheduler &s = Scheduler::instance();
00096     assert(busy_ == 0);
00097   
00098     busy_ = 1;
00099     paused_ = 0;
00100     stime = s.clock();
00101     rtime = time;
00102     assert(rtime >= 0.0);
00103   
00104     s.schedule(this, p, rtime);
00105 }
00106 
00107 void MacTdmaTimer::stop(Packet *p) 
00108 {
00109     Scheduler &s = Scheduler::instance();
00110     assert(busy_);
00111   
00112     if(paused_ == 0)
00113         s.cancel((Event *)p);
00114 
00115     // Should free the packet p.
00116     Packet::free(p);
00117   
00118     busy_ = 0;
00119     paused_ = 0;
00120     stime = 0.0;
00121     rtime = 0.0;
00122 }
00123 
00124 /* Slot timer for TDMA scheduling. */
00125 void SlotTdmaTimer::handle(Event *e)
00126 {       
00127     busy_ = 0;
00128     paused_ = 0;
00129     stime = 0.0;
00130     rtime = 0.0;
00131   
00132     mac->slotHandler(e);
00133 }
00134 
00135 /* Receive Timer */
00136 void RxPktTdmaTimer::handle(Event *e) 
00137 {       
00138     busy_ = 0;
00139     paused_ = 0;
00140     stime = 0.0;
00141     rtime = 0.0;
00142   
00143     mac->recvHandler(e);
00144 }
00145 
00146 /* Send Timer */
00147 void TxPktTdmaTimer::handle(Event *e) 
00148 {       
00149     busy_ = 0;
00150     paused_ = 0;
00151     stime = 0.0;
00152     rtime = 0.0;
00153     
00154     mac->sendHandler(e);
00155 }
00156 
00157 /* ======================================================================
00158    TCL Hooks for the simulator
00159    ====================================================================== */
00160 static class MacTdmaClass : public TclClass {
00161 public:
00162     MacTdmaClass() : TclClass("Mac/Tdma") {}
00163     TclObject* create(int, const char*const*) {
00164         return (new MacTdma(&PMIB));
00165     }
00166 } class_mac_tdma;
00167 
00168 
00169 // Mac Tdma definitions
00170 // Frame format:
00171 // Pamble Slot1 Slot2 Slot3...
00172 MacTdma::MacTdma(PHY_MIB* p) : 
00173     Mac(), mhSlot_(this), mhTxPkt_(this), mhRxPkt_(this){
00174     /* Global variables setting. */
00175     // Setup the phy specs.
00176     phymib_ = p;
00177     
00178     /* Get the parameters of the link (which in bound in mac.cc, 2M by default),
00179        the packet length within one TDMA slot (1500 byte by default), 
00180        and the max number of nodes (64) in the simulations.*/
00181     bind("slot_packet_len_", &slot_packet_len_);
00182     bind("max_node_num_", &max_node_num_);
00183     
00184     //  slot_packet_len_ = 1500;
00185     //  max_node_num_ = 64;
00186     // Calculate the slot time based on the MAX allowed data length.
00187     slot_time_ = DATA_Time(slot_packet_len_);
00188     
00189     /* Calsulate the max slot num within on frame from max node num.
00190        In the simple case now, they are just equal. 
00191     */
00192     max_slot_num_ = max_node_num_;
00193     
00194     /* Much simplified centralized scheduling algorithm for single hop
00195        topology, like WLAN etc. 
00196     */
00197     // Initualize the tdma schedule and preamble data structure.
00198     tdma_schedule_ = new int[max_slot_num_];
00199     tdma_preamble_ = new int[max_slot_num_];
00200 
00201     /* Do each node's initialization. */
00202     // Record the initial active node number.
00203     active_node_++;
00204 
00205     if (active_node_ > max_node_num_) {
00206         printf("Too many nodes taking part in the simulations, aborting...\n");
00207         exit(-1);
00208     }
00209     
00210     // Initial channel / transceiver states. 
00211     tx_state_ = rx_state_ = MAC_IDLE;
00212     tx_active_ = 0;
00213 
00214     // Initialy, the radio is off. NOTE: can't use radioSwitch(OFF) here.
00215     radio_active_ = 0;
00216 
00217     // Do slot scheduling.
00218     re_schedule();
00219 
00220     /* Deal with preamble. */
00221     // Can't send anything in the first frame.
00222     slot_count_ = FIRST_ROUND;
00223     tdma_preamble_[slot_num_] = NOTHING_TO_SEND;
00224 
00225     //Start the Slot timer..
00226     mhSlot_.start((Packet *) (& intr_), 0);  
00227 }
00228 
00229 /* similar to 802.11, no cached node lookup. */
00230 int MacTdma::command(int argc, const char*const* argv)
00231 {
00232     if (argc == 3) {
00233         if (strcmp(argv[1], "log-target") == 0) {
00234             logtarget_ = (NsObject*) TclObject::lookup(argv[2]);
00235             if(logtarget_ == 0)
00236                 return TCL_ERROR;
00237             return TCL_OK;
00238         }
00239     }
00240     return Mac::command(argc, argv);
00241 }
00242 
00243 
00244 /* ======================================================================
00245    Debugging Routines
00246    ====================================================================== */
00247 void MacTdma::trace_pkt(Packet *p) 
00248 {
00249     struct hdr_cmn *ch = HDR_CMN(p);
00250     struct hdr_mac_tdma* dh = HDR_MAC_TDMA(p);
00251     u_int16_t *t = (u_int16_t*) &dh->dh_fc;
00252 
00253     fprintf(stderr, "\t[ %2x %2x %2x %2x ] %x %s %d\n",
00254         *t, dh->dh_duration,
00255         ETHER_ADDR(dh->dh_da), ETHER_ADDR(dh->dh_sa),
00256         index_, packet_info.name(ch->ptype()), ch->size());
00257 }
00258 
00259 void MacTdma::dump(char *fname)
00260 {
00261     fprintf(stderr, "\n%s --- (INDEX: %d, time: %2.9f)\n", fname, 
00262         index_, Scheduler::instance().clock());
00263     
00264     fprintf(stderr, "\ttx_state_: %x, rx_state_: %x, idle: %d\n", 
00265         tx_state_, rx_state_, is_idle());
00266     fprintf(stderr, "\tpktTx_: %lx, pktRx_: %lx, callback: %lx\n", 
00267         (long) pktTx_, (long) pktRx_, (long) callback_);
00268 }
00269 
00270 
00271 /* ======================================================================
00272    Packet Headers Routines
00273    ====================================================================== */
00274 int MacTdma::hdr_dst(char* hdr, int dst )
00275 {
00276     struct hdr_mac_tdma *dh = (struct hdr_mac_tdma*) hdr;
00277     if(dst > -2)
00278         STORE4BYTE(&dst, (dh->dh_da));
00279     return ETHER_ADDR(dh->dh_da);
00280 }
00281 
00282 int MacTdma::hdr_src(char* hdr, int src )
00283 {
00284     struct hdr_mac_tdma *dh = (struct hdr_mac_tdma*) hdr;
00285     if(src > -2)
00286         STORE4BYTE(&src, (dh->dh_sa));
00287   
00288     return ETHER_ADDR(dh->dh_sa);
00289 }
00290 
00291 int MacTdma::hdr_type(char* hdr, u_int16_t type) 
00292 {
00293     struct hdr_mac_tdma *dh = (struct hdr_mac_tdma*) hdr;
00294     if(type)
00295         STORE2BYTE(&type,(dh->dh_body));
00296     return GET2BYTE(dh->dh_body);
00297 }
00298 
00299 /* Test if the channel is idle. */
00300 int MacTdma::is_idle() {
00301     if(rx_state_ != MAC_IDLE)
00302         return 0;
00303     if(tx_state_ != MAC_IDLE)
00304         return 0;
00305     return 1;
00306 }
00307 
00308 /* Do the slot re-scheduling:
00309    The idea of postphone the slot scheduling for one slot time may be useful.
00310 */
00311 void MacTdma::re_schedule() {
00312     static int slot_pointer = 0;
00313     // Record the start time of the new schedule.
00314     start_time_ = NOW;
00315     /* Seperate slot_num_ and the node id: 
00316        we may have flexibility as node number changes.
00317     */
00318     slot_num_ = slot_pointer++;
00319     tdma_schedule_[slot_num_] = (char) index_;
00320 }
00321 
00322 /* To handle incoming packet. */
00323 void MacTdma::recv(Packet* p, Handler* h) {
00324     struct hdr_cmn *ch = HDR_CMN(p);
00325     
00326     /* Incoming packets from phy layer, send UP to ll layer. 
00327        Now, it is in receiving mode. 
00328     */
00329     if (ch->direction() == hdr_cmn::UP) {
00330         // Since we can't really turn the radio off at lower level, 
00331         // we just discard the packet.
00332         if (!radio_active_) {
00333             free(p);
00334             //printf("<%d>, %f, I am sleeping...\n", index_, NOW);
00335             return;
00336         }
00337 
00338         sendUp(p);
00339         //printf("<%d> packet recved: %d\n", index_, tdma_pr_++);
00340         return;
00341     }
00342     
00343     /* Packets coming down from ll layer (from ifq actually),
00344        send them to phy layer. 
00345        Now, it is in transmitting mode. */
00346     callback_ = h;
00347     state(MAC_SEND);
00348     sendDown(p);
00349     //printf("<%d> packet sent down: %d\n", index_, tdma_ps_++);
00350 }
00351 
00352 void MacTdma::sendUp(Packet* p) 
00353 {
00354     struct hdr_cmn *ch = HDR_CMN(p);
00355 
00356     /* Can't receive while transmitting. Should not happen...?*/
00357     if (tx_state_ && ch->error() == 0) {
00358         printf("<%d>, can't receive while transmitting!\n", index_);
00359         ch->error() = 1;
00360     };
00361 
00362     /* Detect if there is any collision happened. should not happen...?*/
00363     if (rx_state_ == MAC_IDLE) {
00364         SET_RX_STATE(MAC_RECV);     // Change the state to recv.
00365         pktRx_ = p;                 // Save the packet for timer reference.
00366 
00367         /* Schedule the reception of this packet, 
00368            since we just see the packet header. */
00369         double rtime = TX_Time(p);
00370         assert(rtime >= 0);
00371 
00372         /* Start the timer for receiving, will end when receiving finishes. */
00373         mhRxPkt_.start(p, rtime);
00374     } else {
00375         /* Note: we don't take the channel status into account, 
00376            as collision should not happen...
00377         */
00378         printf("<%d>, receiving, but the channel is not idle....???\n", index_);
00379     }
00380 }
00381 
00382 /* Actually receive data packet when RxPktTimer times out. */
00383 void MacTdma::recvDATA(Packet *p){
00384     /*Adjust the MAC packet size: strip off the mac header.*/
00385     struct hdr_cmn *ch = HDR_CMN(p);
00386     ch->size() -= ETHER_HDR_LEN;
00387     ch->num_forwards() += 1;
00388 
00389     /* Pass the packet up to the link-layer.*/
00390     uptarget_->recv(p, (Handler*) 0);
00391 }
00392 
00393 /* Send packet down to the physical layer. 
00394    Need to calculate a certain time slot for transmission. */
00395 void MacTdma::sendDown(Packet* p) {
00396     u_int32_t dst, src, size;
00397   
00398     struct hdr_cmn* ch = HDR_CMN(p);
00399     struct hdr_mac_tdma* dh = HDR_MAC_TDMA(p);
00400 
00401     /* Update the MAC header, same as 802.11 */
00402     ch->size() += ETHER_HDR_LEN;
00403 
00404     dh->dh_fc.fc_protocol_version = MAC_ProtocolVersion;
00405     dh->dh_fc.fc_type       = MAC_Type_Data;
00406     dh->dh_fc.fc_subtype    = MAC_Subtype_Data;
00407     
00408     dh->dh_fc.fc_to_ds      = 0;
00409     dh->dh_fc.fc_from_ds    = 0;
00410     dh->dh_fc.fc_more_frag  = 0;
00411     dh->dh_fc.fc_retry      = 0;
00412     dh->dh_fc.fc_pwr_mgt    = 0;
00413     dh->dh_fc.fc_more_data  = 0;
00414     dh->dh_fc.fc_wep        = 0;
00415     dh->dh_fc.fc_order      = 0;
00416 
00417     if((u_int32_t)ETHER_ADDR(dh->dh_da) != MAC_BROADCAST)
00418         dh->dh_duration = DATA_DURATION;
00419     else
00420         dh->dh_duration = 0;
00421 
00422     dst = ETHER_ADDR(dh->dh_da);
00423     src = ETHER_ADDR(dh->dh_sa);
00424     size = ch->size();
00425 
00426     /* buffer the packet to be sent. */
00427     pktTx_ = p;
00428 }
00429 
00430 /* Actually send the packet. */
00431 void MacTdma::send() 
00432 {
00433     u_int32_t dst, src, size;
00434     struct hdr_cmn* ch;
00435     struct hdr_mac_tdma* dh;
00436     double stime;
00437 
00438     /* Check if there is any packet buffered. */
00439     if (!pktTx_) {
00440         printf("<%d>, %f, no packet buffered.\n", index_, NOW);
00441         return;
00442     }
00443 
00444     /* Perform carrier sence...should not be collision...? */
00445     if(!is_idle()) {
00446         /* Note: we don't take the channel status into account, ie. no collision,
00447            as collision should not happen...
00448         */
00449         printf("<%d>, %f, transmitting, but the channel is not idle...???\n", index_, NOW);
00450         return;
00451     }
00452 
00453     ch = HDR_CMN(pktTx_);
00454     dh = HDR_MAC_TDMA(pktTx_);  
00455 
00456     dst = ETHER_ADDR(dh->dh_da);
00457     src = ETHER_ADDR(dh->dh_sa);
00458     size = ch->size();
00459     stime = TX_Time(pktTx_);
00460     ch->txtime() = stime;
00461     
00462     /* Turn on the radio and transmit! */
00463     SET_TX_STATE(MAC_SEND);                          
00464     radioSwitch(ON);
00465 
00466     /* Start a timer that expires when the packet transmission is complete. */
00467     mhTxPkt_.start(pktTx_->copy(), stime);
00468     downtarget_->recv(pktTx_, this);        
00469 
00470     pktTx_ = 0;
00471 }
00472 
00473 // Turn on / off the radio
00474 void MacTdma::radioSwitch(int i) 
00475 {
00476     radio_active_ = i;
00477     //EnergyModel *em = netif_->node()->energy_model();
00478     if (i == ON) {
00479         //if (em && em->sleep())
00480         //em->set_node_sleep(0);
00481         //    printf("<%d>, %f, turn radio ON\n", index_, NOW); 
00482         Phy *p;
00483         p = netif_;
00484         ((WirelessPhy *)p)->node_wakeup();
00485         return;
00486     }
00487 
00488     if (i == OFF) {
00489         //if (em && !em->sleep()) {
00490         //em->set_node_sleep(1);
00491         //    netif_->node()->set_node_state(INROUTE);
00492         Phy *p;
00493         p = netif_;
00494         ((WirelessPhy *)p)->node_sleep();
00495         //    printf("<%d>, %f, turn radio OFF\n", index_, NOW);
00496         return;
00497     }
00498 }
00499 
00500 // make the new preamble.
00501 void MacTdma::makePreamble() 
00502 {
00503     u_int32_t dst;
00504     struct hdr_mac_tdma* dh;
00505     
00506     // If there is a packet buffered, file its destination to preamble.
00507     if (pktTx_) {
00508         dh = HDR_MAC_TDMA(pktTx_);  
00509         dst = ETHER_ADDR(dh->dh_da);
00510         //printf("<%d>, %f, write %d to slot %d in preamble\n", index_, NOW, dst, slot_num_);
00511         tdma_preamble_[slot_num_] = dst;
00512     } else {
00513         //printf("<%d>, %f, write NO_PKT to slot %d in preamble\n", index_, NOW, slot_num_);
00514         tdma_preamble_[slot_num_] = NOTHING_TO_SEND;
00515     }
00516 }
00517 
00518 /* Timers' handlers */
00519 /* Slot Timer:
00520    For the preamble calculation, we should have it:
00521    occupy one slot time,
00522    radio turned on for the whole slot.
00523 */
00524 void MacTdma::slotHandler(Event *e) 
00525 {
00526     // Restart timer for next slot.
00527     mhSlot_.start((Packet *)e, slot_time_);
00528 
00529     // Make a new presamble for next frame.
00530     if ((slot_count_ == active_node_) || (slot_count_ == FIRST_ROUND)) {
00531         //printf("<%d>, %f, make the new preamble now.\n", index_, NOW);
00532         // We should turn the radio on for the whole slot time.
00533         radioSwitch(ON);
00534 
00535         makePreamble();
00536         slot_count_ = 0;
00537         return;
00538     }
00539 
00540     // If it is the sending slot for me.
00541     if (slot_count_ == slot_num_) {
00542         //printf("<%d>, %f, time to send.\n", index_, NOW);
00543         // We have to check the preamble first to avoid the packets coming in the middle.
00544         if (tdma_preamble_[slot_num_] != NOTHING_TO_SEND)
00545             send();
00546         else
00547             radioSwitch(OFF);
00548 
00549         slot_count_++;
00550         return;
00551     }
00552  
00553     // If I am supposed to listen in this slot
00554     if ((tdma_preamble_[slot_count_] == index_) || ((u_int32_t)tdma_preamble_[slot_count_] == MAC_BROADCAST)) {
00555         //printf("<%d>, %f, preamble[%d]=%d, I am supposed to receive now.\n", index_, NOW, slot_count_, tdma_preamble_[slot_count_]);
00556         slot_count_++;
00557 
00558         // Wake up the receive packets.
00559         radioSwitch(ON);
00560         return;
00561     }
00562 
00563     // If I dont send / recv, do nothing.
00564     //printf("<%d>, %f, preamble[%d]=%d, nothing to do now.\n", index_, NOW, slot_count_, tdma_preamble_[slot_count_]);
00565     radioSwitch(OFF);
00566     slot_count_++;
00567     return;
00568 }
00569 
00570 void MacTdma::recvHandler(Event *e) 
00571 {
00572     u_int32_t dst, src; 
00573     int size;
00574     struct hdr_cmn *ch = HDR_CMN(pktRx_);
00575     struct hdr_mac_tdma *dh = HDR_MAC_TDMA(pktRx_);
00576 
00577     /* Check if any collision happened while receiving. */
00578     if (rx_state_ == MAC_COLL) 
00579         ch->error() = 1;
00580 
00581     SET_RX_STATE(MAC_IDLE);
00582   
00583     /* check if this packet was unicast and not intended for me, drop it.*/   
00584     dst = ETHER_ADDR(dh->dh_da);
00585     src = ETHER_ADDR(dh->dh_sa);
00586     size = ch->size();
00587 
00588     //printf("<%d>, %f, recv a packet [from %d to %d], size = %d\n", index_, NOW, src, dst, size);
00589 
00590     // Turn the radio off after receiving the whole packet
00591     radioSwitch(OFF);
00592 
00593     /* Ordinary operations on the incoming packet */
00594     // Not a pcket destinated to me.
00595     if ((dst != MAC_BROADCAST) && (dst != (u_int32_t)index_)) {
00596         drop(pktRx_);
00597         return;
00598     }
00599   
00600     /* Now forward packet upwards. */
00601     recvDATA(pktRx_);
00602 }
00603 
00604 /* After transmission a certain packet. Turn off the radio. */
00605 void MacTdma::sendHandler(Event *e) 
00606 {
00607     //  printf("<%d>, %f, send a packet finished.\n", index_, NOW);
00608 
00609     /* Once transmission is complete, drop the packet. 
00610        p  is just for schedule a event. */
00611     SET_TX_STATE(MAC_IDLE);
00612     Packet::free((Packet *)e);
00613   
00614     // Turn off the radio after sending the whole packet
00615     radioSwitch(OFF);
00616 
00617     /* unlock IFQ. */
00618     if(callback_) {
00619         Handler *h = callback_;
00620         callback_ = 0;
00621         h->handle((Event*) 0);
00622     } 
00623 }

Generated on Tue Mar 6 16:47:47 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6