Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

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.
void registerInterface ()
 Register the interface in InterfaceTable.
virtual void finish ()
 Delete all dynamically allocated objects of the module.
virtual void handleLowerMsg (cMessage *)
 Handle messages from lower layer.
virtual void handleUpperMsg (cMessage *)
 Handle messages from upper layer.
virtual void handleSelfMsg (cMessage *)
 Handle self messages such as timers.
virtual MacPktencapsMsg (cMessage *netw)
 Encapsulate the given higher-layer packet into MacPkt.
virtual void receiveChangeNotification (int category, 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

MacPkt * CSMAMacLayer::encapsMsg cMessage *  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.

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

void CSMAMacLayer::finish  )  [protected, virtual]
 

Delete all dynamically allocated objects of the module.

00110 {
00111 }

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

Handle messages 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.

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

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.

00195 {
00196     EV << "timer expired, calling handleUpperMsg again.. time: " << simTime() << endl;
00197 
00198     // timer expired for a buffered frame, try to send again
00199     handleUpperMsg((MacPkt *) msg->contextPointer());
00200 }

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

Handle messages 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.

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

void CSMAMacLayer::initialize int   )  [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") ? 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 InterfaceTable
00058         registerInterface();
00059     }
00060 }

void CSMAMacLayer::receiveChangeNotification int  category,
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.

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

void CSMAMacLayer::registerInterface  )  [protected]
 

Register the interface in InterfaceTable.

00063 {
00064     InterfaceEntry *e = new InterfaceEntry();
00065 
00066     // interface name: NetworkInterface module's name without special characters ([])
00067     char *interfaceName = new char[strlen(parentModule()->fullName()) + 1];
00068     char *d = interfaceName;
00069     for (const char *s = parentModule()->fullName(); *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     InterfaceTable *ift = InterfaceTableAccess().get();
00105     ift->addInterface(e, this);
00106 }


Member Data Documentation

cQueue CSMAMacLayer::macQueue [protected]
 

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

MACAddress CSMAMacLayer::myMacAddr [protected]
 

mac address

int CSMAMacLayer::queueLength [protected]
 

length of the queue

RadioState::State CSMAMacLayer::radioState [protected]
 

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

simtime_t CSMAMacLayer::sendTime [protected]
 

Used to store the last time a message was sent.

cMessage* CSMAMacLayer::timer [protected]
 

Timer for backoff in case the channel is busy.


The documentation for this class was generated from the following files:
Generated on Thu Oct 19 18:22:21 2006 for INET Framework for OMNeT++/OMNEST by  doxygen 1.4.0