INET Framework for OMNeT++/OMNEST
SnrEval.cc
Go to the documentation of this file.
00001 /* -*- mode:c++ -*- ********************************************************
00002  * file:        SnrEval.cc
00003  *
00004  * author:      Marc Loebbers
00005  *              Multi-channel support: Levente Meszaros, Andras Varga
00006  *
00007  * copyright:   (C) 2004 Telecommunication Networks Group (TKN) at
00008  *              Technische Universitaet Berlin, Germany.
00009  *
00010  *              This program is free software; you can redistribute it
00011  *              and/or modify it under the terms of the GNU General Public
00012  *              License as published by the Free Software Foundation; either
00013  *              version 2 of the License, or (at your option) any later
00014  *              version.
00015  *              For further information see file COPYING
00016  *              in the top level directory
00017  ***************************************************************************
00018  * part of:     framework implementation developed by tkn
00019  ***************************************************************************/
00020 
00021 
00022 #include "SnrEval.h"
00023 #include "FWMath.h"
00024 
00025 
00026 
00027 Define_Module(SnrEval);
00028 
00029 SnrEval::SnrEval() : rs(this->getId())
00030 {
00031 }
00032 
00033 void SnrEval::initialize(int stage)
00034 {
00035     BasicSnrEval::initialize(stage);
00036 
00037     if (stage == 0)
00038     {
00039         gate("radioIn")->setDeliverOnReceptionStart(true);
00040 
00041         // read parameters
00042         rs.setChannelNumber(par("channelNumber"));
00043         thermalNoise = FWMath::dBm2mW(par("thermalNoise"));
00044         carrierFrequency = cc->par("carrierFrequency");  // taken from ChannelControl
00045         sensitivity = FWMath::dBm2mW(par("sensitivity"));
00046         pathLossAlpha = par("pathLossAlpha");
00047         if (pathLossAlpha < (double) (cc->par("alpha")))
00048             error("SnrEval::initialize(): pathLossAlpha can't be smaller than in "
00049                   "ChannelControl. Please adjust your omnetpp.ini file accordingly");
00050 
00051         // initialize noiseLevel
00052         noiseLevel = thermalNoise;
00053 
00054         EV << "Initialized channel with noise: " << noiseLevel << " sensitivity: " << sensitivity <<
00055             endl;
00056 
00057         // initialize the pointer of the snrInfo with NULL to indicate
00058         // that currently no message is received
00059         snrInfo.ptr = NULL;
00060 
00061         // no channel switch pending
00062         newChannel = -1;
00063 
00064         // Initialize radio state. If thermal noise is already to high, radio
00065         // state has to be initialized as RECV
00066         rs.setState(RadioState::IDLE);
00067         if (noiseLevel >= sensitivity)
00068             rs.setState(RadioState::RECV);
00069 
00070         WATCH(noiseLevel);
00071         WATCH(rs);
00072     }
00073     else if (stage == 1)
00074     {
00075         // tell initial value to MAC; must be done in stage 1, because they
00076         // subscribe in stage 0
00077         nb->fireChangeNotification(NF_RADIOSTATE_CHANGED, &rs);
00078         nb->fireChangeNotification(NF_RADIO_CHANNEL_CHANGED, &rs);
00079     }
00080     else if (stage == 2)
00081     {
00082         // tell initial channel number to ChannelControl; should be done in
00083         // stage==2 or later, because base class initializes myHostRef in that stage
00084         cc->updateHostChannel(myHostRef, rs.getChannelNumber());
00085     }
00086 }
00087 
00088 void SnrEval::finish()
00089 {
00090     BasicSnrEval::finish();
00091 }
00092 
00093 SnrEval::~SnrEval()
00094 {
00095     // delete messages being received
00096     for (RecvBuff::iterator it = recvBuff.begin(); it!=recvBuff.end(); ++it)
00097         delete it->first;
00098 }
00099 
00100 void SnrEval::handleMessage(cMessage *msg)
00101 {
00102     if (msg->getArrivalGateId()==uppergateIn && !msg->isPacket())
00103     {
00104         cPolymorphic *ctrl = msg->removeControlInfo();
00105         handleCommand(msg->getKind(), ctrl);
00106         delete msg;
00107     }
00108     else
00109     {
00110         BasicSnrEval::handleMessage(msg); // let base class do it
00111     }
00112 }
00113 
00124 void SnrEval::handleUpperMsg(AirFrame *frame)
00125 {
00126     if (rs.getState() == RadioState::TRANSMIT)
00127         error("Trying to send a message while already transmitting -- MAC should "
00128               "take care this does not happen");
00129 
00130     if (frame->getControlInfo()!=NULL)
00131         error("Setting control info (here: %s) on frames is not supported", frame->getControlInfo()->getClassName());
00132 
00133     // if a packet was being received, it is corrupted now as should be treated as noise
00134     if (snrInfo.ptr != NULL)
00135     {
00136         EV << "Sending a message while receiving another. The received one is now corrupted.\n";
00137 
00138         // remove the snr information stored for the message currently being
00139         // received. This message is treated as noise now and the
00140         // receive power has to be added to the noiseLevel
00141 
00142         // delete the pointer to indicate that no message is being received
00143         snrInfo.ptr = NULL;
00144         // clear the snr list
00145         snrInfo.sList.clear();
00146         // add the receive power to the noise level
00147         noiseLevel += snrInfo.rcvdPower;
00148     }
00149 
00150     // now we are done with all the exception handling and can take care
00151     // about the "real" stuff
00152 
00153     // change radio status
00154     rs.setState(RadioState::TRANSMIT);
00155     EV << "sending, changing RadioState to TRANSMIT\n";
00156     nb->fireChangeNotification(NF_RADIOSTATE_CHANGED, &rs);
00157 
00158     cMessage *timer = new cMessage(NULL, TRANSM_OVER);
00159     scheduleAt(simTime() + frame->getDuration(), timer);
00160     sendDown(frame);
00161 }
00162 
00163 void SnrEval::handleCommand(int msgkind, cPolymorphic *ctrl)
00164 {
00165     if (msgkind==PHY_C_CONFIGURERADIO)
00166     {
00167         // extract new channel number
00168         PhyControlInfo *phyCtrl = check_and_cast<PhyControlInfo *>(ctrl);
00169         int newChannel = phyCtrl->getChannelNumber();
00170         double newBitrate = phyCtrl->getBitrate();
00171         delete ctrl;
00172 
00173         if (newChannel!=-1)
00174         {
00175             EV << "Command received: change to channel " << newChannel << "\n";
00176 
00177             // do it
00178             if (rs.getChannelNumber()==newChannel)
00179                 EV << "Right on that channel, nothing to do\n"; // fine, nothing to do
00180             else if (rs.getState()==RadioState::TRANSMIT) {
00181                 EV << "We're transmitting right now, remembering to change after it's completed\n";
00182                 this->newChannel = newChannel;
00183             } else
00184                 changeChannel(newChannel); // change channel right now
00185         }
00186         if (newBitrate!=-1)
00187         {
00188             EV << "Command received: change bitrate to " << (newBitrate/1e6) << "Mbps\n";
00189 
00190             // do it
00191             if (rs.getBitrate()==newBitrate)
00192                 EV << "Right at that bitrate, nothing to do\n"; // fine, nothing to do
00193             else if (rs.getState()==RadioState::TRANSMIT) {
00194                 EV << "We're transmitting right now, remembering to change after it's completed\n";
00195                 this->newBitrate = newBitrate;
00196             } else
00197                 setBitrate(newBitrate); // change bitrate right now
00198         }
00199     }
00200     else
00201         error("unknown command (msgkind=%d)", msgkind);
00202 }
00203 
00212 void SnrEval::handleSelfMsg(cMessage *msg)
00213 {
00214     if (msg->getKind() == TRANSM_OVER)
00215     {
00216         if (noiseLevel < sensitivity)
00217         {
00218             // set the RadioState to IDLE
00219             rs.setState(RadioState::IDLE);
00220             EV << "transmission over, switch to idle mode (state:IDLE)\n";
00221             nb->fireChangeNotification(NF_RADIOSTATE_CHANGED, &rs);
00222         }
00223         else
00224         {
00225             // set the RadioState to RECV
00226             rs.setState(RadioState::RECV);
00227             EV << "transmission over but noise level too high, switch to recv mode (state:RECV)\n";
00228             nb->fireChangeNotification(NF_RADIOSTATE_CHANGED, &rs);
00229         }
00230 
00231         // delete the timer
00232         delete msg;
00233 
00234         // switch channel if it needs be
00235         if (newChannel!=-1)
00236         {
00237             changeChannel(newChannel);
00238             newChannel = -1;
00239         }
00240     }
00241     else
00242         error("Internal error: unknown self-message `%s'", msg->getName());
00243 }
00244 
00245 
00269 void SnrEval::handleLowerMsgStart(AirFrame * frame)
00270 {
00271     // Calculate the receive power of the message
00272 
00273     // calculate distance
00274     const Coord& myPos = getMyPosition();
00275     const Coord& framePos = frame->getSenderPos();
00276     double distance = myPos.distance(framePos);
00277 
00278     // calculate receive power
00279     double rcvdPower = calcRcvdPower(frame->getPSend(), distance);
00280 
00281     // store the receive power in the recvBuff
00282     recvBuff[frame] = rcvdPower;
00283 
00284     // if receive power is bigger than sensitivity and if not sending
00285     // and currently not receiving another message and the message has
00286     // arrived in time
00287     // NOTE: a message may have arrival time in the past here when we are
00288     // processing ongoing transmissions during a channel change
00289     if (frame->getArrivalTime() == simTime() && rcvdPower >= sensitivity && rs.getState() != RadioState::TRANSMIT && snrInfo.ptr == NULL)
00290     {
00291         EV << "receiving frame " << frame->getName() << endl;
00292 
00293         // Put frame and related SnrList in receive buffer
00294         SnrList snrList;        //defined in SnrList.h!!
00295         snrInfo.ptr = frame;
00296         snrInfo.rcvdPower = rcvdPower;
00297         snrInfo.sList = snrList;
00298 
00299         // add initial snr value
00300         addNewSnr();
00301 
00302         if (rs.getState() != RadioState::RECV)
00303         {
00304             // publish new RadioState
00305             rs.setState(RadioState::RECV);
00306             EV << "publish new RadioState:RECV\n";
00307             nb->fireChangeNotification(NF_RADIOSTATE_CHANGED, &rs);
00308         }
00309     }
00310     // receive power is too low or another message is being sent or received
00311     else
00312     {
00313         EV << "frame " << frame->getName() << " is just noise\n";
00314         //add receive power to the noise level
00315         noiseLevel += rcvdPower;
00316 
00317         // if a message is being received add a new snr value
00318         if (snrInfo.ptr != NULL)
00319         {
00320             // update snr info for currently being received message
00321             EV << "add new snr value to snr list of message being received\n";
00322             addNewSnr();
00323         }
00324 
00325         // update the RadioState if the noiseLevel exceeded the threshold
00326         // and the radio is currently not in receive or in send mode
00327         if (noiseLevel >= sensitivity && rs.getState() == RadioState::IDLE)
00328         {
00329             // publish new RadioState
00330             rs.setState(RadioState::RECV);
00331             EV << "publish new RadioState:RECV\n";
00332             nb->fireChangeNotification(NF_RADIOSTATE_CHANGED, &rs);
00333         }
00334     }
00335 }
00336 
00337 
00348 void SnrEval::handleLowerMsgEnd(AirFrame * frame)
00349 {
00350     // check if message has to be send to the decider
00351     if (snrInfo.ptr == frame)
00352     {
00353         EV << "reception of frame over, preparing to send packet to upper layer\n";
00354         // get Packet and list out of the receive buffer:
00355         SnrList list;
00356         list = snrInfo.sList;
00357 
00358         // delete the pointer to indicate that no message is currently
00359         // being received and clear the list
00360         snrInfo.ptr = NULL;
00361         snrInfo.sList.clear();
00362 
00363         // delete the frame from the recvBuff
00364         recvBuff.erase(frame);
00365 
00366         //Don't forget to send:
00367         sendUp(frame, list);
00368         EV << "packet sent to the decider\n";
00369     }
00370     // all other messages are noise
00371     else
00372     {
00373         EV << "reception of noise message over, removing recvdPower from noiseLevel....\n";
00374         // get the rcvdPower and subtract it from the noiseLevel
00375         noiseLevel -= recvBuff[frame];
00376 
00377         // delete message from the recvBuff
00378         recvBuff.erase(frame);
00379 
00380         // update snr info for message currently being received if any
00381         if (snrInfo.ptr != NULL)
00382         {
00383             addNewSnr();
00384         }
00385 
00386         // message should be deleted
00387         delete frame;
00388         EV << "message deleted\n";
00389     }
00390 
00391     // check the RadioState and update if necessary
00392     // change to idle if noiseLevel smaller than threshold and state was
00393     // not idle before
00394     // do not change state if currently sending or receiving a message!!!
00395     if (noiseLevel < sensitivity && rs.getState() == RadioState::RECV && snrInfo.ptr == NULL)
00396     {
00397         // publish the new RadioState:
00398         EV << "new RadioState is IDLE\n";
00399         rs.setState(RadioState::IDLE);
00400         nb->fireChangeNotification(NF_RADIOSTATE_CHANGED, &rs);
00401     }
00402 }
00403 
00404 
00408 void SnrEval::addNewSnr()
00409 {
00410     SnrListEntry listEntry;     // create a new entry
00411     listEntry.time = simTime();
00412     listEntry.snr = snrInfo.rcvdPower / noiseLevel;
00413     snrInfo.sList.push_back(listEntry);
00414 }
00415 
00416 
00422 double SnrEval::calcRcvdPower(double pSend, double distance)
00423 {
00424     double speedOfLight = 300000000.0;
00425     double waveLength = speedOfLight / carrierFrequency;
00426     return (pSend * waveLength * waveLength / (16 * M_PI * M_PI * pow(distance, pathLossAlpha)));
00427 }
00428 
00429 
00430 void SnrEval::changeChannel(int channel)
00431 {
00432     if (channel == rs.getChannelNumber())
00433         return;
00434     if (channel < 0 || channel >= cc->getNumChannels())
00435         error("changeChannel(): channel number %d is out of range (hint: numChannels is a parameter of ChannelControl)", channel);
00436     if (rs.getState() == RadioState::TRANSMIT)
00437         error("changing channel while transmitting is not allowed");
00438 
00439     // if we are currently receiving, must clean that up before moving to different channel
00440     if (rs.getState() == RadioState::RECV)
00441     {
00442         // delete messages being received, and cancel associated self-messages
00443         for (RecvBuff::iterator it = recvBuff.begin(); it!=recvBuff.end(); ++it)
00444         {
00445             AirFrame *frame = it->first;
00446             cMessage *endRxTimer = (cMessage *)frame->getContextPointer();
00447             delete frame;
00448             delete cancelEvent(endRxTimer);
00449         }
00450         recvBuff.clear();
00451     }
00452 
00453     // clear snr info
00454     snrInfo.ptr = NULL;
00455     snrInfo.sList.clear();
00456 
00457     // do channel switch
00458     EV << "Changing channel to " << channel << "\n";
00459 
00460     rs.setChannelNumber(channel);
00461     cc->updateHostChannel(myHostRef, channel);
00462     ChannelControl::TransmissionList tl = cc->getOngoingTransmissions(channel);
00463 
00464     // pick up ongoing transmissions on the new channel
00465     EV << "Picking up ongoing transmissions on new channel:\n";
00466     for (ChannelControl::TransmissionList::const_iterator it = tl.begin(); it != tl.end(); ++it)
00467     {
00468         AirFrame *frame = *it;
00469         // time for the message to reach us
00470         double distance = myHostRef->pos.distance(frame->getSenderPos());
00471         simtime_t propagationDelay = distance / LIGHT_SPEED;
00472 
00473         // if this transmission is on our new channel and it would reach us in the future, then schedule it
00474         if (channel == frame->getChannelNumber())
00475         {
00476             EV << " - (" << frame->getClassName() << ")" << frame->getName() << ": ";
00477 
00478             // if there is a message on the air which will reach us in the future
00479             if (frame->getTimestamp() + propagationDelay >= simTime())
00480             {
00481                 EV << "will arrive in the future, scheduling it\n";
00482 
00483                 // we need to send to each radioIn[] gate
00484                 cGate *radioGate = gate("radioIn");
00485                 for (int i = 0; i < radioGate->size(); i++)
00486                     sendDirect((cMessage*)frame->dup(), frame->getTimestamp() + propagationDelay - simTime(), frame->getDuration(), this, radioGate->getId() + i);
00487             }
00488             // if we hear some part of the message
00489             else if (frame->getTimestamp() + frame->getDuration() + propagationDelay > simTime())
00490             {
00491                 EV << "missed beginning of frame, processing it as noise\n";
00492 
00493                 AirFrame *frameDup = (AirFrame*)frame->dup();
00494                 frameDup->setArrivalTime(frame->getTimestamp() + propagationDelay);
00495                 handleLowerMsgStart(frameDup);
00496                 bufferMsg(frameDup);
00497             }
00498             else
00499             {
00500                 EV << "in the past\n";
00501             }
00502         }
00503     }
00504 
00505     // notify other modules about the channel switch; and actually, radio state has changed too
00506     nb->fireChangeNotification(NF_RADIO_CHANNEL_CHANGED, &rs);
00507     nb->fireChangeNotification(NF_RADIOSTATE_CHANGED, &rs);
00508 }
00509 
00510 void SnrEval::setBitrate(double bitrate)
00511 {
00512     if (this->bitrate == bitrate)
00513         return;
00514     if (bitrate < 0)
00515         error("setBitrate(): bitrate cannot be negative (%g)", bitrate);
00516     if (rs.getState() == RadioState::TRANSMIT)
00517         error("changing the bitrate while transmitting is not allowed");
00518 
00519     EV << "Setting bitrate to " << (bitrate/1e6) << "Mbps\n";
00520     this->bitrate = bitrate;
00521 
00522     //XXX fire some notification?
00523 }
00524