CSMAMacLayer Class Reference

#include <CSMAMacLayer.h>

Inheritance diagram for CSMAMacLayer:

WirelessMacBase INotifiable

List of all members.


Detailed Description

MAC module which provides non-persistent CSMA.

This is an implementation of a simple non-persistent CSMA. The idea of nonpersistent CSMA is "listen before talk". Before attempting to transmit, a station will sense the medium for a carrier signal, which, if present, indicates that some other station is sending.

If the channel is busy a random waiting time is computed and after this time the channel is sensed again. Once the channel gets idle the message is sent. (State of the channel is obtained from SnrEval via NotificationBoard.)

An option of this module is to use a queue. If a packet from the upper layer arrives although there is still another packet waiting for its transmission or being transmitted the new packet can be stored in this queue. The length of this queue can be specified by the user in the omnetpp.ini file. By default the length is 0. If the queue is full or there is no queue (length = 0) new packet(s) will be deleted.

Todo:
Inform upper layers about the full queue!
ATTENTION: Imagine the following scenario:

Several stations receive a broadcast request packet, usally exactly at the same time. They will all try to answer at exactly the same time, i.e. they all will sense the channel at exactly the same time and start to transmit because the channel was sensed idle by all of them. Therefore a small random delay should be built into one/some of the upper layers to simulate a random processing time!

The TestApplLayer e.g. implements such a processing delay!

Author:
Marc L�bbers, Yosia Hadisusanto

Public Member Functions

 CSMAMacLayer ()
virtual ~CSMAMacLayer ()

Protected Member Functions

virtual void initialize (int)
 Initialization of the module and some variables.
virtual void registerInterface ()
 Register the interface in InterfaceTable.
virtual void finish ()
 Delete all dynamically allocated objects of the module.
virtual void handleLowerMsg (cPacket *)
 Handle packets from lower layer.
virtual void handleCommand (cMessage *)
 Handle commands from upper layer.
virtual void handleUpperMsg (cPacket *)
 Handle packets from upper layer.
virtual void handleSelfMsg (cMessage *)
 Handle self messages such as timers.
virtual MacPkt * encapsMsg (cPacket *netw)
 Encapsulate the given higher-layer packet into MacPkt.
virtual void receiveChangeNotification (int category, const cPolymorphic *details)
 Called by the NotificationBoard whenever a change occurs we're interested in.

Protected Attributes

MACAddress myMacAddr
 mac address
RadioState::State radioState
 Current state of the radio (kept updated by receiveChangeNotification()).
cQueue macQueue
 A queue to store packets from upper layer in case another packet is still waiting for transmission..
int queueLength
 length of the queue
cMessage * timer
 Timer for backoff in case the channel is busy.
simtime_t sendTime
 Used to store the last time a message was sent.

Constructor & Destructor Documentation

CSMAMacLayer::CSMAMacLayer (  ) 

00031 {
00032     timer = NULL;
00033 }

CSMAMacLayer::~CSMAMacLayer (  )  [virtual]

00036 {
00037     cancelAndDelete(timer);
00038 }


Member Function Documentation

void CSMAMacLayer::initialize ( int  stage  )  [protected, virtual]

Initialization of the module and some variables.

Reimplemented from WirelessMacBase.

00041 {
00042     WirelessMacBase::initialize(stage);
00043 
00044     if (stage == 0)
00045     {
00046         queueLength = hasPar("queueLength") ? (int)par("queueLength") : 0;
00047         EV << "queueLength = " << queueLength << endl;
00048 
00049         //subscribe for the information of the carrier sense
00050         nb->subscribe(this, NF_RADIOSTATE_CHANGED);
00051 
00052         // initialize the timer
00053         timer = new cMessage("backoff");
00054 
00055         radioState = RadioState::IDLE; // until 1st receiveChangeNotification()
00056 
00057         // get registered in IInterfaceTable
00058         registerInterface();
00059     }
00060 }

void CSMAMacLayer::registerInterface (  )  [protected, virtual]

Register the interface in InterfaceTable.

Referenced by initialize().

00063 {
00064     InterfaceEntry *e = new InterfaceEntry();
00065 
00066     // interface name: NetworkInterface module's name without special characters ([])
00067     char *interfaceName = new char[strlen(getParentModule()->getFullName()) + 1];
00068     char *d = interfaceName;
00069     for (const char *s = getParentModule()->getFullName(); *s; s++)
00070         if (isalnum(*s))
00071             *d++ = *s;
00072     *d = '\0';
00073 
00074     e->setName(interfaceName);
00075     delete [] interfaceName;
00076 
00077     const char *addrstr = par("address");
00078     if (!strcmp(addrstr, "auto"))
00079     {
00080         // assign automatic address
00081         myMacAddr = MACAddress::generateAutoAddress();
00082 
00083         // change module parameter from "auto" to concrete address
00084         par("address").setStringValue(myMacAddr.str().c_str());
00085     }
00086     else
00087     {
00088         myMacAddr.setAddress(addrstr);
00089     }
00090     e->setMACAddress(myMacAddr);
00091 
00092     // generate interface identifier for IPv6
00093     e->setInterfaceToken(myMacAddr.formInterfaceIdentifier());
00094 
00095     // MTU on 802.11 = ?
00096     e->setMtu(1500);  // FIXME
00097 
00098     // capabilities
00099     e->setBroadcast(true);
00100     e->setMulticast(true);
00101     e->setPointToPoint(false);
00102 
00103     // add
00104     IInterfaceTable *ift = InterfaceTableAccess().get();
00105     ift->addInterface(e, this);
00106 }

void CSMAMacLayer::finish (  )  [protected, virtual]

Delete all dynamically allocated objects of the module.

00110 {
00111 }

void CSMAMacLayer::handleLowerMsg ( cPacket *  msg  )  [protected, virtual]

Handle packets from lower layer.

Compare the address of this Host with the destination address in frame. If they are equal or the frame is broadcast, we send this frame to the upper layer. If not delete it.

Implements WirelessMacBase.

00214 {
00215     MacPkt *mac = check_and_cast<MacPkt *>(msg);
00216 
00217     //only foward to upper layer if message is for me or broadcast
00218     if (mac->getDestAddr() == myMacAddr || mac->getDestAddr().isBroadcast())
00219     {
00220         EV << "sending pkt to upper...\n";
00221         sendUp(mac);
00222     }
00223     else
00224     {
00225         EV << "packet not for me, deleting...\n";
00226         delete mac;
00227     }
00228 }

void CSMAMacLayer::handleCommand ( cMessage *  msg  )  [protected, virtual]

Handle commands from upper layer.

Implements WirelessMacBase.

00114 {
00115     // no commands supported by CSMAMacLayer
00116     error("Non-packet message arrived from higher layer: (%s)%s", msg->getClassName(), msg->getName());
00117 }

void CSMAMacLayer::handleUpperMsg ( cPacket *  msg  )  [protected, virtual]

Handle packets from upper layer.

First it has to be checked whether a frame is currently being transmitted or waiting to be transmitted. If so the newly arrived message is stored in a queue. If there is no queue or it is full print a warning.

Before transmitting a frame it is tested whether the channel is busy at the moment or not. If the channel is busy, a short random time will be generated and the MacPkt is buffered for this time, before a next attempt to send the packet is started.

If channel is idle the frame will be transmitted immediately.

Implements WirelessMacBase.

Referenced by handleSelfMsg().

00133 {
00134     MacPkt *mac = encapsMsg(msg);
00135 
00136     // message has to be queued if another message is waiting to be send
00137     // or if we are already trying to send another message
00138 
00139     // the comparison with sendTime is necessary so that concurrently
00140     // arriving messages are handled sequentially. As soon as one
00141     // message arrived at simTime() is passed to lower layers all other
00142     // messages arriving at the same time will be buffered.
00143     if (timer->isScheduled() || radioState == RadioState::TRANSMIT || sendTime == simTime())
00144     {
00145 
00146         // if there is no queue the message will be deleted
00147         if (queueLength == 0)
00148         {
00149             EV << "New packet arrived though another is still waiting for being sent, "
00150                 " and buffer size is zero. New packet is deleted.\n";
00151             // TODO: Signal this to upper layer!
00152             delete mac;
00153             return;
00154         }
00155 
00156         // the queue is not full yet so we can queue the message
00157         if (macQueue.length() < queueLength)
00158         {
00159             EV << "already transmitting, putting pkt into queue...\n";
00160             macQueue.insert(mac);
00161             return;
00162         }
00163         // queue is full, message has to be deleted
00164         else
00165         {
00166             EV << "New packet arrived, but queue is FULL, so new packet is deleted\n";
00167             // TODO: Signal this to upper layer!!
00168             delete mac;
00169             return;
00170         }
00171     }
00172 
00173     // no message is scheduled for sending or currently being sent
00174 
00175     // check the radio status and transmit the message if the channel is
00176     // idle. Otherwise backoff for a random time and try again
00177     if (radioState == RadioState::IDLE)
00178     {
00179         EV << "CHANNEL IDLE, send...\n";
00180         sendDown(mac);
00181         //store the sending time
00182         sendTime = simTime();
00183     }
00184     else
00185     {
00186         timer->setContextPointer(mac);
00187         simtime_t randomTime = intuniform(0, 10) / 100.0;
00188         scheduleAt(simTime() + randomTime, timer);
00189         EV << "CHANNEL BUSY, I will try to retransmit at " << simTime() + randomTime << ".\n";
00190     }
00191 
00192 }

void CSMAMacLayer::handleSelfMsg ( cMessage *  msg  )  [protected, virtual]

Handle self messages such as timers.

After the timer expires try to retransmit the message by calling handleUpperMsg again.

Implements WirelessMacBase.

00200 {
00201     EV << "timer expired, calling handleUpperMsg again.. time: " << simTime() << endl;
00202 
00203     // timer expired for a buffered frame, try to send again
00204     handleUpperMsg((MacPkt *) msg->getContextPointer());
00205 }

MacPkt * CSMAMacLayer::encapsMsg ( cPacket *  netw  )  [protected, virtual]

Encapsulate the given higher-layer packet into MacPkt.

Encapsulates the received network-layer packet into a MacPkt and set all needed header fields.

Referenced by handleUpperMsg().

00235 {
00236     MacPkt *pkt = new MacPkt(netw->getName());
00237     pkt->setBitLength(272);
00238 
00239     // copy dest address from the Control Info attached to the network
00240     // mesage by the network layer
00241     Ieee802Ctrl *ctrl = check_and_cast<Ieee802Ctrl *>(netw->removeControlInfo());
00242 
00243     EV << "ctrl removed, mac addr=" << ctrl->getDest() << endl;
00244     pkt->setDestAddr(ctrl->getDest());
00245 
00246     //delete the control info
00247     delete ctrl;
00248 
00249     //set the src address to own mac address
00250     pkt->setSrcAddr(myMacAddr);
00251 
00252     //encapsulate the network packet
00253     pkt->encapsulate(netw);
00254     EV << "pkt encapsulated\n";
00255 
00256     return pkt;
00257 }

void CSMAMacLayer::receiveChangeNotification ( int  category,
const cPolymorphic *  details 
) [protected, virtual]

Called by the NotificationBoard whenever a change occurs we're interested in.

Update the internal copy of the RadioState.

If the RadioState switched from TRANSMIT to IDLE and there are still messages in the queue, call handleUpperMsg in order to try to send those now.

Implements INotifiable.

00267 {
00268     Enter_Method("receiveChangeNotification(%s, %s)", notificationCategoryName(category),
00269                  details?details->info().c_str() : "n/a");
00270     printNotificationBanner(category, details);
00271 
00272     if (category == NF_RADIOSTATE_CHANGED)
00273     {
00274         // update the local copy of the radio state
00275         radioState = check_and_cast<RadioState *>(details)->getState();
00276 
00277         // NOTE: we may be invoked during INIT STAGE 1 too, when SnrEval notifies us
00278         // about the initial radio state. This function has to work correctly
00279         // even when called during initialization phase!
00280 
00281         // if the channel is idle now, the queue is not empty and no timer
00282         // is scheduled, this means that sending the previous message is
00283         // complete and the next one can be taken out of the queue
00284         if (radioState == RadioState::IDLE && !macQueue.empty() && !timer->isScheduled())
00285         {
00286             timer->setContextPointer(macQueue.pop());
00287             simtime_t randomTime = intuniform(0, 10) / 100.0;
00288             scheduleAt(simTime() + randomTime, timer);
00289             EV << "taking next pkt out of queue, schedule at " << simTime() + randomTime << endl;
00290         }
00291     }
00292 }


Member Data Documentation

mac address

Referenced by encapsMsg(), handleLowerMsg(), and registerInterface().

Current state of the radio (kept updated by receiveChangeNotification()).

Referenced by handleUpperMsg(), initialize(), and receiveChangeNotification().

cQueue CSMAMacLayer::macQueue [protected]

A queue to store packets from upper layer in case another packet is still waiting for transmission..

Referenced by handleUpperMsg(), and receiveChangeNotification().

int CSMAMacLayer::queueLength [protected]

length of the queue

Referenced by handleUpperMsg(), and initialize().

cMessage* CSMAMacLayer::timer [protected]

Timer for backoff in case the channel is busy.

Referenced by CSMAMacLayer(), handleUpperMsg(), initialize(), receiveChangeNotification(), and ~CSMAMacLayer().

simtime_t CSMAMacLayer::sendTime [protected]

Used to store the last time a message was sent.

Referenced by handleUpperMsg().


The documentation for this class was generated from the following files:

Generated on Fri Mar 20 18:51:18 2009 for INET Framework for OMNeT++/OMNEST by  doxygen 1.5.5