#include <CSMAMacLayer.h>
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. | |
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. |
CSMAMacLayer::CSMAMacLayer | ( | ) |
CSMAMacLayer::~CSMAMacLayer | ( | ) | [virtual] |
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] |
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 }
MACAddress CSMAMacLayer::myMacAddr [protected] |
RadioState::State CSMAMacLayer::radioState [protected] |
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] |
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] |