NetAnimTrace.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2010 Andras Varga
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU Lesser General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser General Public License
00015 // along with this program; if not, see <http://www.gnu.org/licenses/>.
00016 //
00017 
00018 #include "NetAnimTrace.h"
00019 
00020 #if OMNETPP_VERSION >= 0x0401
00021 
00022 Define_Module(NetAnimTrace);
00023 
00024 simsignal_t NetAnimTrace::messageSentSignal;
00025 
00026 // TODO: after release of OMNeT++ 4.1 final, update this code to similar class in omnetpp/contrib/util
00027 
00028 void NetAnimTrace::initialize()
00029 {
00030     if (!par("enabled").boolValue())
00031         return;
00032 
00033     const char *filename = par("filename");
00034     f.open(filename, std::ios::out | std::ios::trunc);
00035     if (f.fail())
00036         throw cRuntimeError("Cannot open file \"%s\" for writing", filename);
00037 
00038     dump();
00039 
00040     messageSentSignal  = registerSignal("messageSent");
00041     simulation.getSystemModule()->subscribe(POST_MODEL_CHANGE, this);
00042     simulation.getSystemModule()->subscribe(messageSentSignal, this);
00043 }
00044 
00045 void NetAnimTrace::handleMessage(cMessage *msg)
00046 {
00047     throw cRuntimeError("This module does not handle messages");
00048 }
00049 
00050 void NetAnimTrace::finish()
00051 {
00052     f.close();
00053 }
00054 
00055 void NetAnimTrace::dump()
00056 {
00057     cModule *parent = simulation.getSystemModule();
00058     for (cModule::SubmoduleIterator it(parent); !it.end(); it++)
00059         if (it() != this)
00060             addNode(it());
00061     for (cModule::SubmoduleIterator it(parent); !it.end(); it++)
00062         if (it() != this)
00063             for (cModule::GateIterator ig(it()); !ig.end(); ig++)
00064                 if (ig()->getType()==cGate::OUTPUT && ig()->getNextGate())
00065                     addLink(ig());
00066 }
00067 
00068 void NetAnimTrace::receiveSignal(cComponent *source, simsignal_t signalID, cObject *obj)
00069 {
00070     if (signalID == messageSentSignal && !source->isModule())
00071     {
00072         // record a "packet sent" line
00073         cChannel *channel = (cChannel *)source;
00074         cModule *srcModule = channel->getSourceGate()->getOwnerModule();
00075         if (isRelevantModule(srcModule))
00076         {
00077             cModule *destModule = channel->getSourceGate()->getNextGate()->getOwnerModule();
00078             cITimestampedValue *v = check_and_cast<cITimestampedValue *>(obj);
00079             if (dynamic_cast<cDatarateChannel *>(channel))
00080             {
00081                 cDatarateChannel *datarateChannel = (cDatarateChannel *)channel;
00082                 cMessage *msg = check_and_cast<cMessage *>(v->objectValue(signalID));
00083                 simtime_t duration = msg->isPacket() ? ((cPacket*)msg)->getBitLength() / datarateChannel->getDatarate() : 0.0;
00084                 simtime_t delay = datarateChannel->getDelay();
00085                 simtime_t fbTx = v->getTimestamp(signalID);
00086                 simtime_t lbTx = fbTx + duration;
00087                 simtime_t fbRx = fbTx + delay;
00088                 simtime_t lbRx = lbTx + delay;
00089                 f << fbTx << " P " << srcModule->getId() << " " << destModule->getId() << " " << lbTx << " " << fbRx << " " << lbRx << "\n";
00090             }
00091             else if (dynamic_cast<cDelayChannel *>(channel))
00092             {
00093                 cDelayChannel *delayChannel = (cDelayChannel *)channel;
00094                 simtime_t fbTx = v->getTimestamp(signalID);
00095                 simtime_t fbRx = fbTx + delayChannel->getDelay();
00096                 f << fbTx << " P " << srcModule->getId() << " " << destModule->getId() << " " << fbTx << " " << fbRx << " " << fbRx << "\n";
00097             }
00098         }
00099     }
00100     else if (signalID == POST_MODEL_CHANGE)
00101     {
00102         // record dynamic "node created" and "link created" lines.
00103         // note: at the time of writing, NetAnim did not support "link removed" and "node removed" lines
00104         if (dynamic_cast<cPostModuleAddNotification *>(obj))
00105         {
00106             cPostModuleAddNotification *notification = (cPostModuleAddNotification *)obj;
00107             if (isRelevantModule(notification->module))
00108                 addNode(notification->module);
00109         }
00110         else if (dynamic_cast<cPostGateConnectNotification *>(obj))
00111         {
00112             cPostGateConnectNotification *notification = (cPostGateConnectNotification *)obj;
00113             if (isRelevantModule(notification->gate->getOwnerModule()))
00114                 addLink(notification->gate);
00115         }
00116     }
00117 }
00118 
00119 bool NetAnimTrace::isRelevantModule(cModule *mod)
00120 {
00121     return mod->getParentModule() == simulation.getSystemModule();
00122 }
00123 
00124 void NetAnimTrace::addNode(cModule *mod)
00125 {
00126     double x, y;
00127     resolveNodeCoordinates(mod, x, y);
00128     f << simTime() << " N " << mod->getId() << " " << x << " " << y << "\n";
00129 }
00130 
00131 void NetAnimTrace::addLink(cGate *gate)
00132 {
00133     f << simTime() << " L " << gate->getOwnerModule()->getId() << " " << gate->getNextGate()->getOwnerModule()->getId() << "\n";
00134 }
00135 
00136 double toDouble(const char *s, double defaultValue)
00137 {
00138    if (!s || !*s)
00139        return defaultValue;
00140    char *end;
00141    double d = strtod(s, &end);
00142    return (end && *end) ? 0.0 : d; // return 0.0 on error, instead of throwing an exception
00143 }
00144 
00145 void NetAnimTrace::resolveNodeCoordinates(cModule *submod, double& x, double& y)
00146 {
00147     // choose some defaults
00148     x = 600 * dblrand();
00149     y = 400 * dblrand();
00150 
00151     // and be content with them if there is no "p" tag in the display string
00152     cDisplayString& ds = submod->getDisplayString();
00153     if (!ds.containsTag("p"))
00154         return;
00155 
00156     // the following code is based on Tkenv (modinsp.cc, getSubmoduleCoords())
00157 
00158     // read x,y coordinates from "p" tag
00159     x = toDouble(ds.getTagArg("p",0), x);
00160     y = toDouble(ds.getTagArg("p",1), y);
00161 
00162     double sx = 20;
00163     double sy = 20;
00164 
00165     const char *layout = ds.getTagArg("p",2); // matrix, row, column, ring, exact etc.
00166 
00167     // modify x,y using predefined layouts
00168     if (!layout || !*layout)
00169     {
00170         // we're happy
00171     }
00172     else if (!strcmp(layout,"e") || !strcmp(layout,"x") || !strcmp(layout,"exact"))
00173     {
00174         int dx = toDouble(ds.getTagArg("p",3), 0);
00175         int dy = toDouble(ds.getTagArg("p",4), 0);
00176         x += dx;
00177         y += dy;
00178     }
00179     else if (!strcmp(layout,"r") || !strcmp(layout,"row"))
00180     {
00181         int dx = toDouble(ds.getTagArg("p",3), 2*sx);
00182         x += submod->getIndex()*dx;
00183     }
00184     else if (!strcmp(layout,"c") || !strcmp(layout,"col") || !strcmp(layout,"column"))
00185     {
00186         int dy = toDouble(ds.getTagArg("p",3), 2*sy);
00187         y += submod->getIndex()*dy;
00188     }
00189     else if (!strcmp(layout,"m") || !strcmp(layout,"matrix"))
00190     {
00191         int columns = toDouble(ds.getTagArg("p",3), 5);
00192         int dx = toDouble(ds.getTagArg("p",4), 2*sx);
00193         int dy = toDouble(ds.getTagArg("p",5), 2*sy);
00194         x += (submod->getIndex() % columns)*dx;
00195         y += (submod->getIndex() / columns)*dy;
00196     }
00197     else if (!strcmp(layout,"i") || !strcmp(layout,"ri") || !strcmp(layout,"ring"))
00198     {
00199         int rx = toDouble(ds.getTagArg("p",3), (sx+sy)*submod->size()/4);
00200         int ry = toDouble(ds.getTagArg("p",4), rx);
00201 
00202         x += (int) floor(rx - rx*sin(submod->getIndex()*2*PI/submod->size()));
00203         y += (int) floor(ry - ry*cos(submod->getIndex()*2*PI/submod->size()));
00204     }
00205     else
00206     {
00207         throw cRuntimeError("invalid layout `%s' in `p' tag of display string", layout);
00208     }
00209 }
00210 
00211 #endif  // OMNETPP_VERSION
00212 
00213 
00214