Implementation of B-MAC (called also Berkeley MAC, Low Power Listening or LPL). More...
#include <BMacLayer.h>
Inherits BaseMacLayer.
Public Member Functions | |
virtual void | initialize (int) |
Initialization of the module and some variables. | |
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 void | handleLowerControl (cMessage *msg) |
Handle control messages from lower layer. | |
Protected Types | |
enum | States { INIT, SLEEP, CCA, SEND_PREAMBLE, WAIT_DATA, SEND_DATA, WAIT_TX_DATA_OVER, WAIT_ACK, SEND_ACK, WAIT_ACK_TX } |
MAC states. More... | |
enum | TYPES { BMAC_PREAMBLE = 191, BMAC_DATA, BMAC_ACK, BMAC_RESEND_DATA, BMAC_ACK_TIMEOUT, BMAC_START_BMAC, BMAC_WAKE_UP, BMAC_SEND_ACK, BMAC_CCA_TIMEOUT, BMAC_ACK_TX_OVER, BMAC_SEND_PREAMBLE, BMAC_STOP_PREAMBLES, BMAC_DATA_TX_OVER, BMAC_DATA_TIMEOUT } |
Types of messages (self messages and packets) the node can process. | |
enum | BMAC_COLORS { GREEN = 1, BLUE = 2, RED = 3, BLACK = 4, YELLOW = 5 } |
Possible colors of the node for animation. | |
typedef std::list< MacPkt * > | MacQueue |
Protected Member Functions | |
void | changeDisplayColor (BMAC_COLORS color) |
Internal function to change the color of the node. | |
void | sendDataPacket () |
Internal function to send the first packet in the queue. | |
void | sendMacAck () |
Internal function to send an ACK. | |
void | sendPreamble () |
Internal function to send one preamble. | |
void | attachSignal (MacPkt *macPkt) |
Internal function to attach a signal to the packet. | |
bool | addToQueue (cMessage *msg) |
Internal function to add a new packet from upper to the queue. | |
Protected Attributes | |
MacQueue | macQueue |
A queue to store packets from upper layer in case another packet is still waiting for transmission. | |
States | macState |
The current state of the protocol. | |
cMessage * | resend_data |
cMessage * | ack_timeout |
cMessage * | start_bmac |
cMessage * | wakeup |
cMessage * | send_ack |
cMessage * | cca_timeout |
cMessage * | ack_tx_over |
cMessage * | send_preamble |
cMessage * | stop_preambles |
cMessage * | data_tx_over |
cMessage * | data_timeout |
DroppedPacket | droppedPacket |
Inspect reasons for dropped packets. | |
int | catDroppedPacket |
Category for dropped packets from BB. | |
int | nicId |
publish dropped packets nic wide | |
double | queueLength |
The maximum length of the queue. | |
bool | animation |
Animate (colorize) the nodes. | |
double | slotDuration |
The duration of the slot in secs. | |
double | bitrate |
The bitrate of transmission. | |
double | headerLength |
The length of the MAC header. | |
double | checkInterval |
The duration of CCA. | |
double | txPower |
Transmission power of the node. | |
bool | useMacAcks |
Use MAC level acks or not. | |
int | maxTxAttempts |
Maximum transmission attempts per data packet, when ACKs are used. | |
bool | stats |
Gather stats at the end of the simulation. | |
Different tracked statistics. | |
long | nbTxDataPackets |
long | nbTxPreambles |
long | nbRxDataPackets |
long | nbRxPreambles |
long | nbMissedAcks |
long | nbRecvdAcks |
long | nbDroppedDataPackets |
long | nbTxAcks |
Help variables for the acknowledgment process. | |
int | lastDataPktSrcAddr |
int | lastDataPktDestAddr |
int | txAttempts |
Implementation of B-MAC (called also Berkeley MAC, Low Power Listening or LPL).
The protocol works as follows: each node is allowed to sleep for slotDuration. After waking up, it first checks the channel for ongoing transmissions. If a transmission is catched (a preamble is received), the node stays awake for at most slotDuration and waits for the actual data packet. If a node wants to send a packet, it first sends preambles for at least slotDuration, thus waking up all nodes in its transmission radius and then sends out the data packet. If a mac-level ack is required, then the receiver sends the ack immediately after receiving the packet (no preambles) and the sender waits for some time more before going back to sleep.
B-MAC is designed for low traffic, low power communication in WSN and is one of the most widely used protocols (e.g. it is part of TinyOS). The finite state machine of the protocol is given in the below figure:
B-MAC Layer - finite state machine
A paper describing this implementation can be found at: http://www.omnet-workshop.org/2011/uploads/slides/OMNeT_WS2011_S5_C1_Foerster.pdf
Definition at line 56 of file BMacLayer.h.
enum BMacLayer::States [protected] |
MAC states.
The MAC states help to keep track what the MAC is actually trying to do. INIT -- node has just started and its status is unclear SLEEP -- node sleeps, but accepts packets from the network layer CCA -- Clear Channel Assessment - MAC checks whether medium is busy SEND_PREAMBLE -- node sends preambles to wake up all nodes WAIT_DATA -- node has received at least one preamble from another node and wiats for the actual data packet SEND_DATA -- node has sent enough preambles and sends the actual data packet WAIT_TX_DATA_OVER -- node waits until the data packet sending is ready WAIT_ACK -- node has sent the data packet and waits for ack from the receiving node SEND_ACK -- node send an ACK back to the sender WAIT_ACK_TX -- node waits until the transmission of the ack packet is over
Definition at line 118 of file BMacLayer.h.
{ INIT, //0 SLEEP, //1 CCA, //2 SEND_PREAMBLE, //3 WAIT_DATA, //4 SEND_DATA, //5 WAIT_TX_DATA_OVER, //6 WAIT_ACK, //7 SEND_ACK, //8 WAIT_ACK_TX //9 };
bool BMacLayer::addToQueue | ( | cMessage * | msg | ) | [protected] |
Internal function to add a new packet from upper to the queue.
Encapsulates the received network-layer packet into a MacPkt and set all needed header fields.
Definition at line 624 of file BMacLayer.cc.
References catDroppedPacket, droppedPacket, NetwToMacControlInfo::getNextHopMac(), headerLength, macQueue, macState, BaseMacLayer::myMacAddr, nicId, BaseMacLayer::PACKET_DROPPED, Blackboard::publishBBItem(), queueLength, BaseLayer::sendControlUp(), DroppedPacket::setReason(), and BaseModule::utility.
Referenced by handleUpperMsg().
{ if (macQueue.size() >= queueLength) { // queue is full, message has to be deleted debugEV << "New packet arrived, but queue is FULL, so new packet is" " deleted\n"; msg->setName("MAC ERROR"); msg->setKind(PACKET_DROPPED); sendControlUp(msg); droppedPacket.setReason(DroppedPacket::QUEUE); utility->publishBBItem(catDroppedPacket, &droppedPacket, nicId); nbDroppedDataPackets++; return false; } MacPkt *macPkt = new MacPkt(msg->getName()); macPkt->setBitLength(headerLength); NetwToMacControlInfo* cInfo = static_cast<NetwToMacControlInfo*> (msg->removeControlInfo()); //EV<<"CSMA received a message from upper layer, name is " // << msg->getName() <<", CInfo removed, mac addr=" // << cInfo->getNextHopMac()<<endl; int dest = cInfo->getNextHopMac(); macPkt->setDestAddr(dest); delete cInfo; macPkt->setSrcAddr(myMacAddr); assert(static_cast<cPacket*>(msg)); macPkt->encapsulate(static_cast<cPacket*>(msg)); macQueue.push_back(macPkt); debugEV << "Max queue length: " << queueLength << ", packet put in queue" "\n queue size: " << macQueue.size() << " macState: " << macState << endl; return true; }
void BMacLayer::changeDisplayColor | ( | BMAC_COLORS | color | ) | [protected] |
Internal function to change the color of the node.
Change the color of the node for animation purposes.
Definition at line 677 of file BMacLayer.cc.
References animation, and BaseModule::findHost().
Referenced by handleSelfMsg().
{ if (!animation) return; cDisplayString& dispStr = findHost()->getDisplayString(); //b=40,40,rect,black,black,2" if (color == GREEN) dispStr.setTagArg("b", 3, "green"); //dispStr.parse("b=40,40,rect,green,green,2"); if (color == BLUE) dispStr.setTagArg("b", 3, "blue"); //dispStr.parse("b=40,40,rect,blue,blue,2"); if (color == RED) dispStr.setTagArg("b", 3, "red"); //dispStr.parse("b=40,40,rect,red,red,2"); if (color == BLACK) dispStr.setTagArg("b", 3, "black"); //dispStr.parse("b=40,40,rect,black,black,2"); if (color == YELLOW) dispStr.setTagArg("b", 3, "yellow"); //dispStr.parse("b=40,40,rect,yellow,yellow,2"); }
void BMacLayer::handleLowerControl | ( | cMessage * | msg | ) | [virtual] |
Handle control messages from lower layer.
Handle transmission over messages: either send another preambles or the data packet itself.
Reimplemented from BaseMacLayer.
Definition at line 578 of file BMacLayer.cc.
References MacToPhyInterface::getRadioState(), macState, and BaseMacLayer::phy.
{ // Transmission of one packet is over if(msg->getKind() == MacToPhyInterface::TX_OVER) { if (macState == WAIT_TX_DATA_OVER) { scheduleAt(simTime(), data_tx_over); } if (macState == WAIT_ACK_TX) { scheduleAt(simTime(), ack_tx_over); } } // Radio switching (to RX or TX) ir over, ignore switching to SLEEP. else if(msg->getKind() == MacToPhyInterface::RADIO_SWITCHING_OVER) { // we just switched to TX after CCA, so simply send the first // sendPremable self message if ((macState == SEND_PREAMBLE) && (phy->getRadioState() == Radio::TX)) { scheduleAt(simTime(), send_preamble); } if ((macState == SEND_ACK) && (phy->getRadioState() == Radio::TX)) { scheduleAt(simTime(), send_ack); } // we were waiting for acks, but none came. we switched to TX and now // need to resend data if ((macState == SEND_DATA) && (phy->getRadioState() == Radio::TX)) { scheduleAt(simTime(), resend_data); } } else { debugEV << "control message with wrong kind -- deleting\n"; } delete msg; }
void BMacLayer::handleLowerMsg | ( | cMessage * | msg | ) | [virtual] |
Handle messages from lower layer.
Handle BMAC preambles and received data packets.
Reimplemented from BaseMacLayer.
Definition at line 558 of file BMacLayer.cc.
References handleSelfMsg().
{ // simply pass the massage as self message, to be processed by the FSM. handleSelfMsg(msg); }
void BMacLayer::handleSelfMsg | ( | cMessage * | msg | ) | [virtual] |
Handle self messages such as timers.
Handle own messages: BMAC_WAKEUP: wake up the node, check the channel for some time. BMAC_CHECK_CHANNEL: if the channel is free, check whether there is something in the queue and switch the radio to TX. When switched to TX, (in receiveBBItem), the node will start sending preambles for a full slot duration. If the channel is busy, stay awake to receive message. Schedule a timeout to handle false alarms. BMAC_SEND_PREAMBLES: sending of preambles over. Next time the data packet will be send out (single one). BMAC_TIMEOUT_DATA: timeout the node after a false busy channel alarm. Go back to sleep.
Reimplemented from BaseMacLayer.
Definition at line 223 of file BMacLayer.cc.
References changeDisplayColor(), checkInterval, BaseMacLayer::decapsMsg(), MacToPhyInterface::getRadioState(), macQueue, macState, maxTxAttempts, BaseMacLayer::myMacAddr, BaseMacLayer::phy, Radio::RX, sendDataPacket(), sendMacAck(), sendPreamble(), BaseLayer::sendUp(), MacToPhyInterface::setRadioState(), Radio::SLEEP, slotDuration, Radio::TX, and useMacAcks.
Referenced by handleLowerMsg().
{ switch (macState) { case INIT: if (msg->getKind() == BMAC_START_BMAC) { debugEV << "State INIT, message BMAC_START, new state SLEEP" << endl; changeDisplayColor(BLACK); phy->setRadioState(Radio::SLEEP); macState = SLEEP; scheduleAt(simTime()+dblrand()*slotDuration, wakeup); return; } break; case SLEEP: if (msg->getKind() == BMAC_WAKE_UP) { debugEV << "State SLEEP, message BMAC_WAKEUP, new state CCA" << endl; scheduleAt(simTime() + checkInterval, cca_timeout); phy->setRadioState(Radio::RX); changeDisplayColor(GREEN); macState = CCA; return; } break; case CCA: if (msg->getKind() == BMAC_CCA_TIMEOUT) { // channel is clear // something waiting in eth queue? if (macQueue.size() > 0) { debugEV << "State CCA, message CCA_TIMEOUT, new state" " SEND_PREAMBLE" << endl; phy->setRadioState(Radio::TX); changeDisplayColor(YELLOW); macState = SEND_PREAMBLE; scheduleAt(simTime() + slotDuration, stop_preambles); return; } // if not, go back to sleep and wake up after a full period else { debugEV << "State CCA, message CCA_TIMEOUT, new state SLEEP" << endl; scheduleAt(simTime() + slotDuration, wakeup); macState = SLEEP; phy->setRadioState(Radio::SLEEP); changeDisplayColor(BLACK); return; } } // during CCA, we received a preamble. Go to state WAIT_DATA and // schedule the timeout. if (msg->getKind() == BMAC_PREAMBLE) { nbRxPreambles++; debugEV << "State CCA, message BMAC_PREAMBLE received, new state" " WAIT_DATA" << endl; macState = WAIT_DATA; cancelEvent(cca_timeout); scheduleAt(simTime() + slotDuration + checkInterval, data_timeout); delete msg; return; } // this case is very, very, very improbable, but let's do it. // if in CCA and the node receives directly the data packet, switch to // state WAIT_DATA and re-send the message if (msg->getKind() == BMAC_DATA) { nbRxDataPackets++; debugEV << "State CCA, message BMAC_DATA, new state WAIT_DATA" << endl; macState = WAIT_DATA; cancelEvent(cca_timeout); scheduleAt(simTime() + slotDuration + checkInterval, data_timeout); scheduleAt(simTime(), msg); return; } //in case we get an ACK, we simply dicard it, because it means the end //of another communication if (msg->getKind() == BMAC_ACK) { debugEV << "State CCA, message BMAC_ACK, new state CCA" << endl; delete msg; return; } break; case SEND_PREAMBLE: if (msg->getKind() == BMAC_SEND_PREAMBLE) { debugEV << "State SEND_PREAMBLE, message BMAC_SEND_PREAMBLE, new" " state SEND_PREAMBLE" << endl; sendPreamble(); scheduleAt(simTime() + 0.5f*checkInterval, send_preamble); macState = SEND_PREAMBLE; return; } // simply change the state to SEND_DATA if (msg->getKind() == BMAC_STOP_PREAMBLES) { debugEV << "State SEND_PREAMBLE, message BMAC_STOP_PREAMBLES, new" " state SEND_DATA" << endl; macState = SEND_DATA; txAttempts = 1; return; } break; case SEND_DATA: if ((msg->getKind() == BMAC_SEND_PREAMBLE) || (msg->getKind() == BMAC_RESEND_DATA)) { debugEV << "State SEND_DATA, message BMAC_SEND_PREAMBLE or" " BMAC_RESEND_DATA, new state WAIT_TX_DATA_OVER" << endl; // send the data packet sendDataPacket(); macState = WAIT_TX_DATA_OVER; return; } break; case WAIT_TX_DATA_OVER: if (msg->getKind() == BMAC_DATA_TX_OVER) { if ((useMacAcks) && (lastDataPktDestAddr != L2BROADCAST)) { debugEV << "State WAIT_TX_DATA_OVER, message BMAC_DATA_TX_OVER," " new state WAIT_ACK" << endl; macState = WAIT_ACK; phy->setRadioState(Radio::RX); changeDisplayColor(GREEN); scheduleAt(simTime()+checkInterval, ack_timeout); } else { debugEV << "State WAIT_TX_DATA_OVER, message BMAC_DATA_TX_OVER," " new state SLEEP" << endl; delete macQueue.front(); macQueue.pop_front(); // if something in the queue, wakeup soon. if (macQueue.size() > 0) scheduleAt(simTime() + dblrand()*checkInterval, wakeup); else scheduleAt(simTime() + slotDuration, wakeup); macState = SLEEP; phy->setRadioState(Radio::SLEEP); changeDisplayColor(BLACK); } return; } break; case WAIT_ACK: if (msg->getKind() == BMAC_ACK_TIMEOUT) { // No ACK received. try again or drop. if (txAttempts < maxTxAttempts) { debugEV << "State WAIT_ACK, message BMAC_ACK_TIMEOUT, new state" " SEND_DATA" << endl; txAttempts++; macState = SEND_PREAMBLE; scheduleAt(simTime() + slotDuration, stop_preambles); phy->setRadioState(Radio::TX); changeDisplayColor(YELLOW); } else { debugEV << "State WAIT_ACK, message BMAC_ACK_TIMEOUT, new state" " SLEEP" << endl; //drop the packet delete macQueue.front(); macQueue.pop_front(); // if something in the queue, wakeup soon. if (macQueue.size() > 0) scheduleAt(simTime() + dblrand()*checkInterval, wakeup); else scheduleAt(simTime() + slotDuration, wakeup); macState = SLEEP; phy->setRadioState(Radio::SLEEP); changeDisplayColor(BLACK); nbMissedAcks++; } return; } //ignore and other packets if ((msg->getKind() == BMAC_DATA) || (msg->getKind() == BMAC_PREAMBLE)) { debugEV << "State WAIT_ACK, message BMAC_DATA or BMAC_PREMABLE, new" " state WAIT_ACK" << endl; delete msg; return; } if (msg->getKind() == BMAC_ACK) { debugEV << "State WAIT_ACK, message BMAC_ACK" << endl; MacPkt *mac = static_cast<MacPkt *>(msg); int src = mac->getSrcAddr(); // the right ACK is received.. debugEV << "We are waiting for ACK from : " << lastDataPktDestAddr << ", and ACK came from : " << src << endl; if (src == lastDataPktDestAddr) { debugEV << "New state SLEEP" << endl; nbRecvdAcks++; lastDataPktDestAddr = L2BROADCAST; cancelEvent(ack_timeout); delete macQueue.front(); macQueue.pop_front(); // if something in the queue, wakeup soon. if (macQueue.size() > 0) scheduleAt(simTime() + dblrand()*checkInterval, wakeup); else scheduleAt(simTime() + slotDuration, wakeup); macState = SLEEP; phy->setRadioState(Radio::SLEEP); changeDisplayColor(BLACK); lastDataPktDestAddr = L2BROADCAST; } delete msg; return; } break; case WAIT_DATA: if(msg->getKind() == BMAC_PREAMBLE) { //nothing happens debugEV << "State WAIT_DATA, message BMAC_PREAMBLE, new state" " WAIT_DATA" << endl; nbRxPreambles++; delete msg; return; } if(msg->getKind() == BMAC_ACK) { //nothing happens debugEV << "State WAIT_DATA, message BMAC_ACK, new state WAIT_DATA" << endl; delete msg; return; } if (msg->getKind() == BMAC_DATA) { nbRxDataPackets++; MacPkt *mac = static_cast<MacPkt *>(msg); int dest = mac->getDestAddr(); int src = mac->getSrcAddr(); if ((dest == myMacAddr) || (dest == L2BROADCAST)) { sendUp(decapsMsg(mac)); } else { delete msg; msg = NULL; mac = NULL; } cancelEvent(data_timeout); if ((useMacAcks) && (dest == myMacAddr)) { debugEV << "State WAIT_DATA, message BMAC_DATA, new state" " SEND_ACK" << endl; macState = SEND_ACK; lastDataPktSrcAddr = src; phy->setRadioState(Radio::TX); changeDisplayColor(YELLOW); } else { debugEV << "State WAIT_DATA, message BMAC_DATA, new state SLEEP" << endl; // if something in the queue, wakeup soon. if (macQueue.size() > 0) scheduleAt(simTime() + dblrand()*checkInterval, wakeup); else scheduleAt(simTime() + slotDuration, wakeup); macState = SLEEP; phy->setRadioState(Radio::SLEEP); changeDisplayColor(BLACK); } return; } if (msg->getKind() == BMAC_DATA_TIMEOUT) { debugEV << "State WAIT_DATA, message BMAC_DATA_TIMEOUT, new state" " SLEEP" << endl; // if something in the queue, wakeup soon. if (macQueue.size() > 0) scheduleAt(simTime() + dblrand()*checkInterval, wakeup); else scheduleAt(simTime() + slotDuration, wakeup); macState = SLEEP; phy->setRadioState(Radio::SLEEP); changeDisplayColor(BLACK); return; } break; case SEND_ACK: if (msg->getKind() == BMAC_SEND_ACK) { debugEV << "State SEND_ACK, message BMAC_SEND_ACK, new state" " WAIT_ACK_TX" << endl; // send now the ack packet sendMacAck(); macState = WAIT_ACK_TX; return; } break; case WAIT_ACK_TX: if (msg->getKind() == BMAC_ACK_TX_OVER) { debugEV << "State WAIT_ACK_TX, message BMAC_ACK_TX_OVER, new state" " SLEEP" << endl; // ack sent, go to sleep now. // if something in the queue, wakeup soon. if (macQueue.size() > 0) scheduleAt(simTime() + dblrand()*checkInterval, wakeup); else scheduleAt(simTime() + slotDuration, wakeup); macState = SLEEP; phy->setRadioState(Radio::SLEEP); changeDisplayColor(BLACK); lastDataPktSrcAddr = L2BROADCAST; return; } break; } opp_error("Undefined event of type %d in state %d (Radio state %d)!", msg->getKind(), macState, phy->getRadioState()); }
void BMacLayer::handleUpperMsg | ( | cMessage * | msg | ) | [virtual] |
Handle messages from upper layer.
Check whether the queue is not full: if yes, print a warning and drop the packet. Then initiate sending of the packet, if the node is sleeping. Do nothing, if node is working.
Reimplemented from BaseMacLayer.
Definition at line 160 of file BMacLayer.cc.
References addToQueue(), and macState.
{ bool pktAdded = addToQueue(msg); if (!pktAdded) return; // force wakeup now if (wakeup->isScheduled() && (macState == SLEEP)) { cancelEvent(wakeup); scheduleAt(simTime() + dblrand()*0.1f, wakeup); } }
void BMacLayer::sendMacAck | ( | ) | [protected] |
Internal function to send an ACK.
Send one short preamble packet immediately.
Definition at line 193 of file BMacLayer.cc.
References attachSignal(), headerLength, BaseMacLayer::myMacAddr, and BaseLayer::sendDown().
Referenced by handleSelfMsg().
{ MacPkt* ack = new MacPkt(); ack->setSrcAddr(myMacAddr); ack->setDestAddr(lastDataPktSrcAddr); ack->setKind(BMAC_ACK); ack->setBitLength(headerLength); //attach signal and send down attachSignal(ack); sendDown(ack); nbTxAcks++; //endSimulation(); }
void BMacLayer::sendPreamble | ( | ) | [protected] |
Internal function to send one preamble.
Send one short preamble packet immediately.
Definition at line 176 of file BMacLayer.cc.
References attachSignal(), headerLength, BaseMacLayer::myMacAddr, and BaseLayer::sendDown().
Referenced by handleSelfMsg().
{ MacPkt* preamble = new MacPkt(); preamble->setSrcAddr(myMacAddr); preamble->setDestAddr(L2BROADCAST); preamble->setKind(BMAC_PREAMBLE); preamble->setBitLength(headerLength); //attach signal and send down attachSignal(preamble); sendDown(preamble); nbTxPreambles++; }
bool BMacLayer::animation [protected] |
Animate (colorize) the nodes.
The color of the node reflects its basic status (not the exact state!) BLACK - node is sleeping GREEN - node is receiving YELLOW - node is sending
Definition at line 193 of file BMacLayer.h.
Referenced by changeDisplayColor().