#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::States | 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. | |
|
|
00031 {
00032 timer = NULL;
00033 }
|
|
|
00036 {
00037 cancelAndDelete(timer);
00038 }
|
|
|
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 }
|
|
|
Delete all dynamically allocated objects of the module.
00110 {
00111 }
|
|
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
||||||||||||
|
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
00266 if (category == NF_RADIOSTATE_CHANGED)
00267 {
00268 // update the local copy of the radio state
00269 radioState = check_and_cast<RadioState *>(details)->getState();
00270
00271 // NOTE: we may be invoked during INIT STAGE 1 too, when SnrEval notifies us
00272 // about the initial radio state. This function has to work correctly
00273 // even when called during initialization phase!
00274
00275 EV << "** Radio state update in " << className() << ": " << details->info()
00276 << " (at T=" << simtimeToStr(simTime()) << ")\n";
00277
00278 // if the channel is idle now, the queue is not empty and no timer
00279 // is scheduled, this means that sending the previous message is
00280 // complete and the next one can be taken out of the queue
00281 if (radioState == RadioState::IDLE && !macQueue.empty() && !timer->isScheduled())
00282 {
00283 timer->setContextPointer(macQueue.pop());
00284 double randomTime = intuniform(0, 10) / 100.0;
00285 scheduleAt(simTime() + randomTime, timer);
00286 EV << "taking next pkt out of queue, schedule at " << simTime() + randomTime << endl;
00287 }
00288 }
00289 }
|
|
|
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 }
|
|
|
A queue to store packets from upper layer in case another packet is still waiting for transmission..
|
|
|
mac address
|
|
|
length of the queue
|
|
|
Current state of the radio (kept updated by receiveChangeNotification()).
|
|
|
Used to store the last time a message was sent.
|
|
|
Timer for backoff in case the channel is busy.
|
1.4.1