dup(); send(copy, "out"); }"> dup(); send(copy, "out"); }">

Presentation is loading. Please wait.

Presentation is loading. Please wait.

Introduction to Omnet++ By: Mahsa Soheil Shamaee.

Similar presentations


Presentation on theme: "Introduction to Omnet++ By: Mahsa Soheil Shamaee."— Presentation transcript:

1 Introduction to Omnet++ By: Mahsa Soheil Shamaee

2 Retransmitting the same message In this step we refine the previous model. There we just created another packet if we needed to retransmit. This is OK because the packet didn't contain much, but in real life it's usually more practical to keep a copy of the original packet so that we can re-send it without the need to build it again. What we do here is keep the original packet and send only copies of it. We delete the original when toc's acknowledgement arrives. To make it easier to visually verify the model, we'll include a message sequence number the message names. TicToc Tutorial for OMNeT++ class Tic9 : public cSimpleModule { private: simtime_t timeout; // timeout cMessage *timeoutEvent; // holds pointer to the timeout self-message int seq; // message sequence number cMessage *message; // message that has to be re-sent on timeout public: Tic9(); virtual ~Tic9(); protected: virtual cMessage *generateNewMessage(); virtual void sendCopyOf(cMessage *msg); virtual void initialize(); virtual void handleMessage(cMessage *msg); }; Define_Module(Tic9); Tic9::Tic9() { timeoutEvent = message = NULL; } Tic9::~Tic9() { cancelAndDelete(timeoutEvent); delete message; }

3 TicToc Tutorial for OMNeT++ void Tic9::initialize() { // Initialize variables. seq = 0; timeout = 1.0; timeoutEvent = new cMessage("timeoutEvent"); // Generate and send initial message. EV << "Sending initial message\n"; message = generateNewMessage(); sendCopyOf(message); scheduleAt(simTime()+timeout, timeoutEvent); } cMessage *Tic9::generateNewMessage() { // Generate a message with a different name every time. char msgname[20]; sprintf(msgname, "tic-%d", ++seq); cMessage *msg = new cMessage(msgname); return msg; } void Tic9::sendCopyOf(cMessage *msg) { // Duplicate message and send the copy. cMessage *copy = (cMessage *) msg->dup(); send(copy, "out"); }

4 TicToc Tutorial for OMNeT++ void Tic9::handleMessage(cMessage *msg) { if (msg==timeoutEvent) { // If we receive the timeout event, that means the packet hasn't // arrived in time and we have to re-send it. EV << "Timeout expired, resending message and restarting timer\n"; sendCopyOf(message); scheduleAt(simTime()+timeout, timeoutEvent); } else // message arrived { // Acknowledgement received! EV getName() << "\n"; delete msg; // Also delete the stored message and cancel the timeout event. EV << "Timer cancelled.\n"; cancelEvent(timeoutEvent); delete message; // Ready to send another one. message = generateNewMessage(); sendCopyOf(message); scheduleAt(simTime()+timeout, timeoutEvent);}}

5 TicToc Tutorial for OMNeT++ /** * Sends back an acknowledgement -- or not. */ class Toc9 : public cSimpleModule { protected: virtual void handleMessage(cMessage *msg); }; Define_Module(Toc9); void Toc9::handleMessage(cMessage *msg) { if (uniform(0,1) < 0.1) { EV << "\"Losing\" message " << msg << endl; bubble("message lost"); delete msg; } else { EV << msg << " received, sending back an acknowledgement.\n"; delete msg; send(new cMessage("ack"), "out");}}

6 TicToc Tutorial for OMNeT++ Step 10: More than two nodes Now we'll make a big step: create several tic modules and connect them into a network. For now, we'll keep it simple what they do: one of the nodes generates a message, and the others keep tossing it around in random directions until it arrives at a predetermined destination node. The NED file will need a few changes. First of all, the Txc module will need to have multiple input and output gates: simple Txc10 { parameters: @display("i=block/routing"); gates: input in[]; output out[]; } network Tictoc10 { submodules: tic[6]: Txc10; connections: tic[0].out++ --> { delay = 100ms; } --> tic[1].in++; tic[0].in++ <-- { delay = 100ms; } <-- tic[1].out++; tic[1].out++ --> { delay = 100ms; } --> tic[2].in++; tic[1].in++ <-- { delay = 100ms; } <-- tic[2].out++; tic[1].out++ --> { delay = 100ms; } --> tic[4].in++; tic[1].in++ <-- { delay = 100ms; } <-- tic[4].out++; tic[3].out++ --> { delay = 100ms; } --> tic[4].in++; tic[3].in++ <-- { delay = 100ms; } <-- tic[4].out++; tic[4].out++ --> { delay = 100ms; } --> tic[5].in++; tic[4].in++ <-- { delay = 100ms; } <-- tic[5].out++; }

7 TicToc Tutorial for OMNeT++ class Txc10 : public cSimpleModule { protected: virtual void forwardMessage(cMessage *msg); virtual void initialize(); virtual void handleMessage(cMessage *msg); }; Define_Module(Txc10); void Txc10::initialize() { if (getIndex()==0) { // Boot the process scheduling the initial message as a self-message. char msgname[20]; sprintf(msgname, "tic-%d", getIndex()); cMessage *msg = new cMessage(msgname); scheduleAt(0.0, msg); } void Txc10::handleMessage(cMessage *msg) { if (getIndex()==3) { // Message arrived. EV << "Message " << msg << " arrived.\n"; delete msg; } else { // We need to forward the message. forwardMessage(msg); } void Txc10::forwardMessage(cMessage *msg) { int n = gateSize("out"); int k = intuniform(0,n-1); EV << "Forwarding message " << msg << " on port out[" << k << "]\n"; send(msg, "out", k); }

8 TicToc Tutorial for OMNeT++ Here we created 6 modules as a module vector, and connected them In this version, tic[0] will generate the message to be sent around. This is done in initialize(), with the help of the getIndex() function which returns the index of the module in the vector The meat of the code is the forwardMessage() function which we invoke from handleMessage() whenever a message arrives at the node. It draws a random gate number (size() is the size of the gate vector), and sends out message on that gate

9 TicToc Tutorial for OMNeT++ Step 11: Channels and inner type definitions Our new network definition is getting quite complex and long, especially the connections section. Let's try to simplify it. The first thing we notice is that the connections always use the same delay parameter. It is possible to create types for the connections (they are called channels) similarly to simple modules. We should create a channel type which specifies the delay parameter and we will use that type for all connections in the network. simple Txc11 { parameters: @display("i=block/routing"); gates: input in[]; output out[]; } network Tictoc11{ types: channel Channel extends ned.DelayChannel { delay = 100ms;} submodules: tic[6]: Txc11; connections: tic[0].out++ --> Channel --> tic[1].in++; tic[0].in++ <-- Channel <-- tic[1].out++; tic[1].out++ --> Channel --> tic[2].in++; tic[1].in++ <-- Channel <-- tic[2].out++; tic[1].out++ --> Channel --> tic[4].in++; tic[1].in++ <-- Channel <-- tic[4].out++; tic[3].out++ --> Channel --> tic[4].in++; tic[3].in++ <-- Channel <-- tic[4].out++; tic[4].out++ --> Channel --> tic[5].in++; tic[4].in++ <-- Channel <-- tic[5].out++;} we define the new channel type inside the network definition by adding a types section. This type definition is only visible inside the network. It is called as a local or inner type. You can use simple modules as inner types too, if you wish. Note: We have created the channel by specializing the built-in DelayChannel. (built-in channels can be found inside the ned package. Thats why we used the full type name ned.DelayChannel ) after the extends keyword.

10 TicToc Tutorial for OMNeT++ Step 12: Using two-way connections If we check the connections section a little more, we will realize that each node pair is connected with two connections. One for each direction. OMNeT++ 4 supports two way connections, so let's use them. First of all, we have to define two-way (or so called inout ) gates instead of the separate input and output gates we used previously. simple Txc12 { parameters: @display("i=block/routing"); gates: inout gate[]; } network Tictoc12 { types: channel Channel extends ned.DelayChannel { delay = 100ms; } submodules: tic[6]: Txc12; connections: tic[0].gate++ Channel tic[1].gate++; tic[1].gate++ Channel tic[2].gate++; tic[1].gate++ Channel tic[4].gate++; tic[3].gate++ Channel tic[4].gate++; tic[4].gate++ Channel tic[5].gate++; }

11 TicToc Tutorial for OMNeT++ class Txc12 : public cSimpleModule { protected: virtual void forwardMessage(cMessage *msg); virtual void initialize(); virtual void handleMessage(cMessage *msg); }; Define_Module(Txc12); void Txc12::initialize() { if (getIndex()==0) { char msgname[20]; sprintf(msgname, "tic-%d", getIndex()); cMessage *msg = new cMessage(msgname); scheduleAt(0.0, msg); } void Txc12::forwardMessage(cMessage *msg) { int n = gateSize("gate"); int k = intuniform(0,n-1); EV << "Forwarding message " << msg << " on gate[" << k << "]\n"; send(msg, "gate$o", k); } void Txc12::handleMessage(cMessage *msg) { if (getIndex()==3) { // Message arrived. EV << "Message " << msg << " arrived.\n"; delete msg; } else { forwardMessage(msg); } The special $i and $o suffix after the gate name allows us to use the connection's two direction separately.

12 TicToc Tutorial for OMNeT++ Step 13: Defining our message class In this step the destination address is no longer hardcoded tic[3] -- we draw a random destination, and we'll add the destination address to the message The best way is to subclass cMessage and add destination as a data member. Hand-coding the message class is usually tedious because it contains a lot of boilerplate code, so we let OMNeT++ generate the class for us. The message class specification is in tictoc13.msg:cMessage message TicTocMsg13 { int source; int destination; int hopCount = 0; } The makefile is set up so that the message compiler, opp_msgc is invoked and it generates tictoc13_m.h and tictoc13_m.cc from the message declaration. They will contain a generated TicTocMsg13 class subclassed from cMessage; the class will have getter and setter methods for every field. cMessage We'll include tictoc13_m.h into our C++ code, and we can use TicTocMsg13 as any other class.

13 TicToc Tutorial for OMNeT++ class Txc13 : public cSimpleModule { protected: virtual TicTocMsg13 *generateMessage(); virtual void forwardMessage(TicTocMsg13 *msg); virtual void initialize(); virtual void handleMessage(cMessage *msg); }; Define_Module(Txc13); void Txc13::initialize() { if (getIndex()==0) { // Boot the process scheduling the initial message as a self-message. TicTocMsg13 *msg = generateMessage(); scheduleAt(0.0, msg); } #include "tictoc13_m.h" We'll include tictoc13_m.h into our C++ code, and we can use TicTocMsg13 as any other class. TicTocMsg13 *Txc13::generateMessage() { // Produce source and destination addresses. int src = getIndex(); // our module index int n = size(); // module vector size int dest = intuniform(0,n-2); if (dest==src) dest++; char msgname[20]; sprintf(msgname, "tic-%d-to-%d", src, dest); // Create message object and set source and destination field. TicTocMsg13 *msg = new TicTocMsg13(msgname); msg->setSource(src); msg->setDestination(dest); return msg; }

14 TicToc Tutorial for OMNeT++ void Txc13::handleMessage(cMessage *msg) { TicTocMsg13 *ttmsg = check_and_cast (msg); if (ttmsg->getDestination()==getIndex()) { // Message arrived. EV getHopCount() << " hops.\n"; bubble("ARRIVED, starting new one!"); delete ttmsg; // Generate another one. EV << "Generating another message: "; TicTocMsg13 *newmsg = generateMessage(); EV << newmsg << endl; forwardMessage(newmsg); } else { // We need to forward the message. forwardMessage(ttmsg); } In the argument to handleMessage(), we get the message as a cMessage * pointer. However, we can only access its fields defined in TicTocMsg13 if we cast msg to TicTocMsg13 *. Plain C-style cast ((TicTocMsg13 *)msg) is not safe because if the message is not a TicTocMsg13 after all the program will just crash, causing an error which is difficult to explorecMessage C++ offers a solution which is called dynamic_cast. Here we use check_and_cast<>() which is provided by OMNeT++: it tries to cast the pointer via dynamic_cast, and if it fails it stops the simulation with an error message, similar to the following:check_and_cast<>()

15 TicToc Tutorial for OMNeT++ void Txc13::forwardMessage(TicTocMsg13 *msg) { // Increment hop count. msg->setHopCount(msg->getHopCount()+1); // Same routing as before: random gate. int n = gateSize("gate"); int k = intuniform(0,n-1); EV << "Forwarding message " << msg << " on gate[" << k << "]\n"; send(msg, "gate$o", k); } You can double-click on the messages to open an inspector for them The inspector window displays lots of useful information; the message fields can be seen on the Contents page

16 TicToc Tutorial for OMNeT++ Step 14: Displaying the number of packets sent/received To get an overview at runtime how many messages each node sent or received, we've added two counters to the module class: numSent and numReceived. class Txc14 : public cSimpleModule { private: long numSent; long numReceived; protected: virtual TicTocMsg14 *generateMessage(); virtual void forwardMessage(TicTocMsg14 *msg); virtual void updateDisplay(); virtual void initialize(); virtual void handleMessage(cMessage *msg); }; Define_Module(Txc14); void Txc14::initialize() { // Initialize variables numSent = 0; numReceived = 0; WATCH(numSent); WATCH(numReceived); // Module 0 sends the first message if (getIndex()==0) { // Boot the process scheduling the initial message as a self-message. TicTocMsg14 *msg = generateMessage(); scheduleAt(0.0, msg); }

17 TicToc Tutorial for OMNeT++ void Txc14::handleMessage(cMessage *msg) { TicTocMsg14 *ttmsg = check_and_cast (msg); if (ttmsg->getDestination()==getIndex()) { // Message arrived int hopcount = ttmsg->getHopCount(); EV << "Message " << ttmsg << " arrived after " << hopcount << " hops.\n"; numReceived++; delete ttmsg; bubble("ARRIVED, starting new one!"); // Generate another one. EV << "Generating another message: "; TicTocMsg14 *newmsg = generateMessage(); EV << newmsg << endl; forwardMessage(newmsg); numSent++; if (ev.isGUI()) updateDisplay(); } else { // We need to forward the message. forwardMessage(ttmsg); } void Txc14::updateDisplay() { char buf[40]; sprintf(buf, "rcvd: %ld sent: %ld", numReceived, numSent); getDisplayString().setTagArg("t",0,buf); } It can be also arranged that this info appears above the module icons. The t= display string tag specifies the text; we only need to modify the displays string during runtime.

18 TicToc Tutorial for OMNeT++

19 Step 15: Adding statistics collection The OMNeT++ simulation kernel can record a detailed log about your message exchanges automatically by setting the [Config Tictoc15] network = Tictoc15 record-eventlog = true The previous simulation model does something interesting enough so that we can collect some statistics For example, you may be interested in the average hop count a message has to travel before reaching its destination We'll record in the hop count of every message upon arrival into an output vector (a sequence of (time,value) pairs, sort of a time series) We also calculate mean, standard deviation, minimum, maximum values per node, and write them into a file at the end of the simulation Then we'll use tools from the OMNeT++ IDE to analyse the output files For that, we add an output vector object (which will record the data into Tictoc15-0.vec) and a histogram object (which also calculates mean, etc) to the class

20 TicToc Tutorial for OMNeT++ message TicTocMsg15 { int source; int destination; int hopCount = 0;} simple Txc15{ parameters: @display("i=block/routing"); gates: inout gate[];} network Tictoc15 { types: channel Channel extends ned.DelayChannel { delay = 100ms; } submodules: tic[6]: Txc15; connections: tic[0].gate++ Channel tic[1].gate++; tic[1].gate++ Channel tic[2].gate++; tic[1].gate++ Channel tic[4].gate++; tic[3].gate++ Channel tic[4].gate++; tic[4].gate++ Channel tic[5].gate++;} class Txc15 : public cSimpleModule { private: long numSent; long numReceived; cLongHistogram hopCountStats; cOutVector hopCountVector; protected: virtual TicTocMsg15 *generateMessage(); virtual void forwardMessage(TicTocMsg15 *msg); virtual void initialize(); virtual void handleMessage(cMessage *msg); // The finish() function is called by OMNeT++ at the end of the simulation: virtual void finish(); };

21 TicToc Tutorial for OMNeT++ Define_Module(Txc15); void Txc15::initialize() { // Initialize variables numSent = 0; numReceived = 0; WATCH(numSent); WATCH(numReceived); hopCountStats.setName("hopCountStats"); hopCountStats.setRangeAutoUpper(0, 10, 1.5); hopCountVector.setName("HopCount"); // Module 0 sends the first message if (getIndex()==0) { // Boot the process scheduling the initial message as a self-message. TicTocMsg15 *msg = generateMessage(); scheduleAt(0.0, msg); } void Txc15::handleMessage(cMessage *msg) { TicTocMsg15 *ttmsg = check_and_cast (msg); if (ttmsg->getDestination()==getIndex()) { // Message arrived int hopcount = ttmsg->getHopCount(); EV << "Message " << ttmsg << " arrived after " << hopcount << " hops.\n"; bubble("ARRIVED, starting new one!"); // update statistics. numReceived++; hopCountVector.record(hopcount); hopCountStats.collect(hopcount); delete ttmsg;. }

22 TicToc Tutorial for OMNeT++ void Txc15::finish() { // This function is called by OMNeT++ at the end of the simulation. EV << "Sent: " << numSent << endl; EV << "Received: " << numReceived << endl; EV << "Hop count, min: " << hopCountStats.getMin() << endl; EV << "Hop count, max: " << hopCountStats.getMax() << endl; EV << "Hop count, mean: " << hopCountStats.getMean() << endl; EV << "Hop count, stddev: " << hopCountStats.getStddev() << endl; recordScalar("#sent", numSent); recordScalar("#received", numReceived); hopCountStats.recordAs("hop count"); } hopCountVector.record() call writes the data into Tictoc15-0.vec With a large simulation model or long execution time, the Tictoc15-0.vec file may grow very large To handle this situation, you can specifically disable/enable vector in omnetpp.ini, and you can also specify a simulation time interval in which you're interested (data recorded outside this interval will be discarded) When you begin a new simulation, the existing Tictoc15- 0.vec/sca file gets deleted Scalar data (collected by the histogram object in this simulation) have to be recorded manually, in the finish() function finish() gets invoked on successful completion of the simulation, i.e. not when it's stopped with an error The recordScalar() calls in the code below write into the Tictoc15-0.sca file The files are stored in the results/ subdirectory.

23 TicToc Tutorial for OMNeT++. Step 16: Statistic collection without modifying your model In the previous step we have added statistic collection to our model While we can compute and save any value we wish, usually it is not known at the time of writing the model, what data the enduser will need OMNeT++ 4.1 provides an additional mechanism to record values and events Any model can emit 'signals' that can carry a value or an object The model writer just have to decide what signals to emit, what data to attach to them and when to emit them The enduser can attach 'listeners' to these signals that can process or record these data items This way the model code does not have to contain any code that is specific to the statistics collection and the enduser can freely add additional statistics without even looking into the C++ code We will re-write the statistic collection introduced in the last step to use signals First of all, we can safely remove all statistic related variables from our module. There is no need for the cOutVector and cLongHistogram classes eithercOutVectorcLongHistogram We will need only a single signal that carries the hopCount of the message at the time of message arrival at the destination First we need to define our signal. The arrivalSignal is just an identifier that can be used later to easily refer to our signal

24 TicToc Tutorial for OMNeT++. class Txc16 : public cSimpleModule { private: simsignal_t arrivalSignal; protected: virtual TicTocMsg16 *generateMessage(); virtual void forwardMessage(TicTocMsg16 *msg); virtual void initialize(); virtual void handleMessage(cMessage *msg); }; Define_Module(Txc16); void Txc16::initialize() { arrivalSignal = registerSignal("arrival"); // Module 0 sends the first message if (getIndex()==0) { // Boot the process scheduling the initial message as a self-message. TicTocMsg16 *msg = generateMessage(); scheduleAt(0.0, msg); } We must register all signals before using them The best place to do this is the initialize() method of the module void Txc16::handleMessage(cMessage *msg) { TicTocMsg16 *ttmsg = check_and_cast (msg); if (ttmsg->getDestination()==getIndex()) { // Message arrived int hopcount = ttmsg->getHopCount(); // send a signal emit(arrivalSignal, hopcount); EV << "Message " << ttmsg << " arrived after " << hopcount << " hops.\n"; bubble("ARRIVED, starting new one!"); delete ttmsg; Now we can emit our signal, when the message has arrived to the destination node As we do not have to save or store anything manually, the finish() method can be deleted. We no longer need it

25 TicToc Tutorial for OMNeT++. simple Txc16 { parameters: @signal[arrival](type="long"); @statistic[hopCount](title="hop count"; source="arrival"; record=vector,stats; interpolationmode=none); @display("i=block/routing"); gates: inout gate[]; } network Tictoc16 { types: channel Channel extends ned.DelayChannel { delay = 100ms; } submodules: tic[6]: Txc16; connections: tic[0].gate++ Channel tic[1].gate++; tic[1].gate++ Channel tic[2].gate++; tic[1].gate++ Channel tic[4].gate++; tic[3].gate++ Channel tic[4].gate++; tic[4].gate++ Channel tic[5].gate++; } Define the emitted signal also in the NED file Declaring signals in the NED file allows you to have all information about your module in one place You will see the parameters it takes, its input and output gates, and also the signals and statistics it provides


Download ppt "Introduction to Omnet++ By: Mahsa Soheil Shamaee."

Similar presentations


Ads by Google