|
INET Framework for OMNeT++/OMNEST
|
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