INET Framework for OMNeT++/OMNEST
CSMAMacLayer Class Reference

MAC module which provides non-persistent CSMA. More...

#include <CSMAMacLayer.h>

Inheritance diagram for CSMAMacLayer:
WirelessMacBase INotifiable

List of all members.

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.

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

Constructor & Destructor Documentation

CSMAMacLayer::CSMAMacLayer ( )
{
    timer = NULL;
}
CSMAMacLayer::~CSMAMacLayer ( ) [virtual]
{
    cancelAndDelete(timer);
}

Member Function Documentation

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().

{
    MacPkt *pkt = new MacPkt(netw->getName());
    pkt->setBitLength(272);

    // copy dest address from the Control Info attached to the network
    // mesage by the network layer
    Ieee802Ctrl *ctrl = check_and_cast<Ieee802Ctrl *>(netw->removeControlInfo());

    EV << "ctrl removed, mac addr=" << ctrl->getDest() << endl;
    pkt->setDestAddr(ctrl->getDest());

    //delete the control info
    delete ctrl;

    //set the src address to own mac address
    pkt->setSrcAddr(myMacAddr);

    //encapsulate the network packet
    pkt->encapsulate(netw);
    EV << "pkt encapsulated\n";

    return pkt;
}
void CSMAMacLayer::finish ( ) [protected, virtual]

Delete all dynamically allocated objects of the module.

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

Handle commands from upper layer.

Implements WirelessMacBase.

{
    // no commands supported by CSMAMacLayer
    error("Non-packet message arrived from higher layer: (%s)%s", msg->getClassName(), msg->getName());
}
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.

{
    MacPkt *mac = check_and_cast<MacPkt *>(msg);

    //only foward to upper layer if message is for me or broadcast
    if (mac->getDestAddr() == myMacAddr || mac->getDestAddr().isBroadcast())
    {
        EV << "sending pkt to upper...\n";
        sendUp(mac);
    }
    else
    {
        EV << "packet not for me, deleting...\n";
        delete mac;
    }
}
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.

{
    EV << "timer expired, calling handleUpperMsg again.. time: " << simTime() << endl;

    // timer expired for a buffered frame, try to send again
    handleUpperMsg((MacPkt *) msg->getContextPointer());
}
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().

{
    MacPkt *mac = encapsMsg(msg);

    // message has to be queued if another message is waiting to be send
    // or if we are already trying to send another message

    // the comparison with sendTime is necessary so that concurrently
    // arriving messages are handled sequentially. As soon as one
    // message arrived at simTime() is passed to lower layers all other
    // messages arriving at the same time will be buffered.
    if (timer->isScheduled() || radioState == RadioState::TRANSMIT || sendTime == simTime())
    {

        // if there is no queue the message will be deleted
        if (queueLength == 0)
        {
            EV << "New packet arrived though another is still waiting for being sent, "
                " and buffer size is zero. New packet is deleted.\n";
            // TODO: Signal this to upper layer!
            delete mac;
            return;
        }

        // the queue is not full yet so we can queue the message
        if (macQueue.length() < queueLength)
        {
            EV << "already transmitting, putting pkt into queue...\n";
            macQueue.insert(mac);
            return;
        }
        // queue is full, message has to be deleted
        else
        {
            EV << "New packet arrived, but queue is FULL, so new packet is deleted\n";
            // TODO: Signal this to upper layer!!
            delete mac;
            return;
        }
    }

    // no message is scheduled for sending or currently being sent

    // check the radio status and transmit the message if the channel is
    // idle. Otherwise backoff for a random time and try again
    if (radioState == RadioState::IDLE)
    {
        EV << "CHANNEL IDLE, send...\n";
        sendDown(mac);
        //store the sending time
        sendTime = simTime();
    }
    else
    {
        timer->setContextPointer(mac);
        simtime_t randomTime = intuniform(0, 10) / 100.0;
        scheduleAt(simTime() + randomTime, timer);
        EV << "CHANNEL BUSY, I will try to retransmit at " << simTime() + randomTime << ".\n";
    }

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

Initialization of the module and some variables.

Reimplemented from WirelessMacBase.

{
    WirelessMacBase::initialize(stage);

    if (stage == 0)
    {
        queueLength = hasPar("queueLength") ? (int)par("queueLength") : 0;
        EV << "queueLength = " << queueLength << endl;

        //subscribe for the information of the carrier sense
        nb->subscribe(this, NF_RADIOSTATE_CHANGED);

        // initialize the timer
        timer = new cMessage("backoff");

        radioState = RadioState::IDLE; // until 1st receiveChangeNotification()

        // get registered in IInterfaceTable
        registerInterface();
    }
}
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.

{
    Enter_Method("receiveChangeNotification(%s, %s)", notificationCategoryName(category),
                 details?details->info().c_str() : "n/a");
    printNotificationBanner(category, details);

    if (category == NF_RADIOSTATE_CHANGED)
    {
        // update the local copy of the radio state
        radioState = check_and_cast<RadioState *>(details)->getState();

        // NOTE: we may be invoked during INIT STAGE 1 too, when SnrEval notifies us
        // about the initial radio state. This function has to work correctly
        // even when called during initialization phase!

        // if the channel is idle now, the queue is not empty and no timer
        // is scheduled, this means that sending the previous message is
        // complete and the next one can be taken out of the queue
        if (radioState == RadioState::IDLE && !macQueue.empty() && !timer->isScheduled())
        {
            timer->setContextPointer(macQueue.pop());
            simtime_t randomTime = intuniform(0, 10) / 100.0;
            scheduleAt(simTime() + randomTime, timer);
            EV << "taking next pkt out of queue, schedule at " << simTime() + randomTime << endl;
        }
    }
}
void CSMAMacLayer::registerInterface ( ) [protected, virtual]

Register the interface in InterfaceTable.

Referenced by initialize().

{
    InterfaceEntry *e = new InterfaceEntry();

    // interface name: NetworkInterface module's name without special characters ([])
    char *interfaceName = new char[strlen(getParentModule()->getFullName()) + 1];
    char *d = interfaceName;
    for (const char *s = getParentModule()->getFullName(); *s; s++)
        if (isalnum(*s))
            *d++ = *s;
    *d = '\0';

    e->setName(interfaceName);
    delete [] interfaceName;

    const char *addrstr = par("address");
    if (!strcmp(addrstr, "auto"))
    {
        // assign automatic address
        myMacAddr = MACAddress::generateAutoAddress();

        // change module parameter from "auto" to concrete address
        par("address").setStringValue(myMacAddr.str().c_str());
    }
    else
    {
        myMacAddr.setAddress(addrstr);
    }
    e->setMACAddress(myMacAddr);

    // generate interface identifier for IPv6
    e->setInterfaceToken(myMacAddr.formInterfaceIdentifier());

    // MTU on 802.11 = ?
    e->setMtu(1500);  // FIXME

    // capabilities
    e->setBroadcast(true);
    e->setMulticast(true);
    e->setPointToPoint(false);

    // add
    IInterfaceTable *ift = InterfaceTableAccess().get();
    ift->addInterface(e, this);
}

Member Data Documentation

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().

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

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

simtime_t CSMAMacLayer::sendTime [protected]

Used to store the last time a message was sent.

Referenced by handleUpperMsg().

cMessage* CSMAMacLayer::timer [protected]

Timer for backoff in case the channel is busy.

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


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