#include <CSMAMacLayer.h>
Inheritance diagram for CSMAMacLayer:
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.
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!
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 MacPkt * | encapsMsg (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. |
CSMAMacLayer::CSMAMacLayer | ( | ) |
CSMAMacLayer::~CSMAMacLayer | ( | ) | [virtual] |
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] |
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 }
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.