Skip to main content

OTCL and C++ Linkages with Example - NS2 Tutorial 3

OTcl and C++ Linkages

In this post

  • The linkages between OTcl and C++ is covered.
  • The functions of various TclCL classes were explored.

Network simulator 2 (ns) deals with two different languages OTcl and C++. The OTcl is mainly for beginners that act as a frontend to test, analyze the components of networks. But C++ on the other hand runs in the background and usually deals with implementation of Queues, protocols, packets, agents, applications, etc. However when C++ modules are introduced, it is necessary to see how it is linking with the OTcl objects. This chapter deals this.

 

3.1 NS-2 Architecture

Network Simulator 2 (NS-2) deals with two different languages C++ and OTcl.  Mainly OTcl is interpreted language and C++ is Compiled language.

The advantage of both the languages in NS2 is not compromised as both the languages have their own pros and cons.

OTcl  

·       Preferable for beginners (to start simulation even without knowing much about ns2)

·       Runs in the front end. (Since interpreter is slow in execution, OTcl preferred in the front end)

·       Interpretation is fast and execution is slow (Since it accepts changes fast, the source code can be modified easily to verify the network performance)

C++

·       Mainly deals with implementation of network terminologies like queues, packets, agents, applications, routing algorithms, etc.

·       Preferable for medium and advanced users

·       Its execution is fast and compilation is slow. (Compilers usually are slow in compilation and hence they are running in the background to make the execution faster)

With these above, we can conclude that OTcl and C++ both need to be in their places for faster execution.

3.2 Code Overview

Consider the example:

        set tcp1 [new Agent/TCP]

     set sink1 [new Agent/TCPSink]

set udp1 [new Agent/UDP]

The above code is a Tcl code that calls TcpAgent, TCPSink Agent and FTP Application. All three are C++ modules that are executing in the backend.

These three Tcl Objects links with the C++ Objects as given in the Table

OTcl Object

C++ Class

Location of C++ file

Agent/TCP

TcpClass

~ns-2.35/tcp/tcp.cc

Agent/TCPSink

TcpSinkClass

~ns-2.35/tcp/tcp-sink.cc

Agent/UDP

UdpAgentClass

~ns-2.35/apps/udp.cc

 

As shown in the table, there should be a link between the OTcl and C++. NS-2 defines a interface called TclCL (~tclcl/) that contains some classes that makes the mapping between OTcl and C++.

There are some lists of classes and this chapter will be focusing on four main classes with their member functions. These classes are defined in ~tclcl-xx/Tcl.h. The following table lists the purpose of each class with their class names

Tcl

Contains method to access the interpreter

TclObject

This is the base class of all Simulated object libraries

TclClass

Provides the mapping between the classes of interpreted hierarchy and compiled hierarchy

TclCommand

Used to define the global interpreter command

EmbeddedTcl

Contains method to load the C++ commands for easier configuration

InstVar

Contains methods to access C++ member variables as OTcl instance variables.

 

The location of these classes are found in the ~tclcl/Tcl.[h, .cc], ~tclcl/Tcl2.cc, ~tclcl/tcl-object.tcl, etc. These classes are used in building ns.

Class Tcl

The class Tcl that contains methods to access the interpreted hierarchy. The methods can be used by the programmer to develop the C++ code.

Class Tcl provides the following operations

·       Obtain a reference to Tcl instance

o   Tcl& tcl = Tcl::instance();

o   tcl is the reference and all the methods can be accessed using tcl.eval(), tcl.evalf(), etc.

·       Invoke Tcl procedures

o   Four methods are there to invoke the command through the instance tcl.

o   tcl.eval() -

o   tcl.eval(char* a) – executes ‘a’ through the interpreter.

o   tcl.evalf(const char* a…..)- this is similar like a printf() statement where the format specifiers are used.

o   tcl.evalc(const char* a)- it preserves the argument string ‘a’ as a constant.

Example:

tcl.evalf(“%d is the packet id”, packet_id);

tcl.evalc(“put this to the screen”);

·       Passing Results to/from the Interpreter

o   Two functions are used to pass results to/from the interpreter.

o   tcl.result(const char* a) – pass the string a to the interpreter back.

o   tcl.resultf(const char* fmt, ...)

o   the following script will help you on this

if (strcmp(argv[1], "HELLO") == 0)

{

tcl.resultf("%d", seq_no);

return TCL_OK;

}

tcl.result("Invalid operation specified");

return TCL_ERROR;

·       Error Reporting and Exit

o   Errors are often reported to the interpreter using the function error().

o   tcl.error(const char* a) performs the following functions:

§  write a to stdout;

§  write tcl_->result to stdout;

§  exit with error code 1.

·       There are other operations and hash Functions within the Interpreter, they are

o   tcl.enter(TclObject* o) – to insert an object in the hash table while creating the TclObject

o   tcl.lookup(char* a) will retrieve the TclObject with the name a.

o   tcl.remove(TclObject* o) will delete references to the TclObject.

o   These functions are used internally by the class TclObject and class TclClass.

 

Class TclClass and Class TclObject

TclClass is a pure virtual class. Classes derived from this base class provide two functions:

·       It does the mapping between the classes of interpreted hierarchy and compiled hierarchy;

·       This class provides methods to create instance for TclObject.

// ~ns-2.35/tcp/tcp.cc

static class TcpClass : public TclClass {

public:

            TcpClass() : TclClass("Agent/TCP") {}

            TclObject* create(int , const char*const*) {

                        return (new TcpAgent());

            }

       } class_tcp;

As an example, consider the code segment above which shows the syntax of the TcpClass. It is derived from class TclClass, and is associated with the class TcpAgent. This will will create the instance of TcpAgent and thus create new objects in the class TcpAgent. The compiled class hierarchy for TcpAgent is that it derives from Agent, that in turn derives from TclObject.

Here is the observation from this definition:

·       This TclClass defines only the constructor and it shows the compiled hierarchy.

·       ns will execute the TcpClass constructor for the static variable class_tcp, when it is first started.

·       The constructor specifies the interpreted class explicitly as Agent/TCP. This also specifies the interpreted hierarchy.

·       The convention in ns is to use the character slash (’/’) is a separator. For any given class A/B/C/D, the class A/B/C/D is a sub-class of A/B/C that is itself a sub-class of A/B, that, in turn, is a sub-class of A. and A is the sub class of TclObject. In our case above, the TclClass constructor creates two classes, Agent/TCP sub-class of Agent sub- class of TclObject.

·       The TcpClass::create method returns TclObject in the class TcpAgent.

·       When the user specifies new Agent/TCP in the tcl file, the class TcpClass::create is invoked and thus a shadow object is created.

Consider the Example shown called as the Amplifier Agent that amplifies the given value in to multiples times

/* A Simple agent that does the amplification of a given value to 3 fold and more. The name of the agent is represented as TSPAgent as The SPecial Agent that does the amplification */

//Header file declaration

#include <stdio.h>

#include <string.h>

#include "agent.h"

class TSPAgent : public Agent {

public:

                  TSPAgent();

protected:

      int command(int argc, const char*const* argv);

private:

      int    amp1, amp2, amp3;

      void   APrivateFunc(void);

};

 

static class TSPAgentClass : public TclClass {

public:

      TSPAgentClass() : TclClass("Agent/AMPLIFY") {}

      TclObject* create(int, const char*const*) {

return(new TSPAgent());

      }

} class_tsp_agent;

 

TSPAgent::TSPAgent() : Agent(PT_UDP) {

      bind("Ampli1", &amp1);

      bind("Ampli2", &amp2);

      bind("Ampli3", &amp3);

}

int TSPAgent::command(int argc, const char*const* argv) {

      if(argc == 2) {

                  if(strcmp(argv[1], "call-the-private-function") == 0) {

            APrivateFunc();

            return(TCL_OK);

                  }

      }

      return(Agent::command(argc, argv));

}

void TSPAgent::APrivateFunc(void) {

      Tcl& tcl = Tcl::instance();

      tcl.eval("puts \"Message From the Private Function\"");

      tcl.evalf("puts \"  The Amplified Value is %d and the factor is 2 \"", amp1*amp1);

      tcl.evalf("puts \"  The Amplified Value is %d and the factor is 3 \"", amp2*amp2*amp2);

      tcl.evalf("puts \"  The Amplified Value is %d and the factor is 4 \"", amp3*amp3*amp3*amp3);

}

In the above example, the Line 1 to 3, includes the header files, the Agent class is available in the agent.h file.

Line 5 to 13, declares a class with three integer variables and two functions command() and APrivateFunc().

Line 14 to 19, includes a static class that does the mapping between the OTCL and C++ and also contains the code that instantiates the TclObject. The name of the Agent here is Agent/AMPLIFY which indicates it is a interpreted hierarchy and the static class TSPAgentClass is the compiled hierarchy class. Clearly, the TclClass does the mapping between the Interpreted hierarchy and Compiled hierarchy.

Line 20 to 24, declares the constructor and all the agents should act on a Packet, so this agent acts in the UDP Packet, PT_UDP. There are three binding OTCL factors Ampli1, Ampli2 and Ampli3 that maps to C++’s amp1, amp2 and amp3 respectively.

 Line 25 to 31, implements the command function, that processes the arguments passed from the OTCL.  If the argv[1] and the call-the-private-function is validated, that calls the APrivateFunc();

Line 32 to 38, the implementation of APrivateFunc() that amplifies the values.

Here is the Tcl file to test the above agent

 

#the name of the file is agent.tcl

set myagent [new Agent/AMPLIFY]

$myagent set Ampli1 3

$myagent set Ampli2 4

$myagent set Ampli3 5

$myagent call-the-private-function

To execute the above agent, here are the steps

·       Copy the ampagent.cc file in ~ns-allinone-2.35/ns-2.35/newagent

·       Make an entry in the ~ns-2.35/Makefile.in

            Make an entry in the OBJ_CC =

                                    newfolder/ampagent.o \

·       In the shell prompt, go to ~ns-2.35 and give the following commands one by one

./configure

Make

·       Run the file agent.tcl

·       If warnings are there, the set the default values in the ns-default.tcl file (~ns-2.35/tcl/lib) as shown below

o   Agent/AMPLIFY set Ampli1 1

o   Agent/AMPLIFY set Ampli2 1

o   Agent/AMPLIFY set Ampli3 1

Output:

Message From the Private Function

  The Amplified Value is 9 and the factor is 2

  The Amplified Value is 64 and the factor is 3

  The Amplified Value is 625 and the factor is 4

Comments

Popular posts from this blog

Installing ns3 in Ubuntu 22.04 | Complete Instructions

In this post, we are going to see how to install ns-3.36.1 in Ubuntu 22.04. You can follow the video for complete details Tools used in this simulation: NS3 version ns-3.36.1  OS Used: Ubuntu 22.04 LTS Installation of NS3 (ns-3.36.1) There are some changes in the ns3 installation procedure and the dependencies. So open a terminal and issue the following commands Step 1:  Prerequisites $ sudo apt update In the following packages, all the required dependencies are taken care and you can install all these packages for the complete use of ns3. $ sudo apt install g++ python3 python3-dev pkg-config sqlite3 cmake python3-setuptools git qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools gir1.2-goocanvas-2.0 python3-gi python3-gi-cairo python3-pygraphviz gir1.2-gtk-3.0 ipython3 openmpi-bin openmpi-common openmpi-doc libopenmpi-dev autoconf cvs bzr unrar gsl-bin libgsl-dev libgslcblas0 wireshark tcpdump sqlite sqlite3 libsqlite3-dev  libxml2 libxml2-dev libc6-dev libc6-dev-i386 libc...

Installation of NS2 (ns-2.35) in Ubuntu 20.04

Installation of NS2 (ns-2.35) in Ubuntu 20.04 LTS Step 1: Install the basic libraries like      $] sudo apt install build-essential autoconf automake libxmu-dev Step 2: install gcc-4.8 and g++-4.8 open the file using sudo mode $] sudo nano /etc/apt/sources.list Include the following line deb http://in.archive.ubuntu.com/ubuntu bionic main universe $] sudo apt update $] sudo apt install gcc-4.8 g++-4.8 Step 3:  Unzip the ns2 packages to home folder $] tar zxvf ns-allinone-2.35.tar.gz $] cd ns-allinone-2.35/ns-2.35 Modify the following make files. ~ns-2.35/Makefile.in Change @CC@ to gcc-4.8 change @CXX@ to g++-4.8 ~nam-1.15/Makefile.in ~xgraph-12.2/Makefile.in ~otcl-1.14/Makefile.in Change in all places  @CC@ to gcc-4.8 @CPP@ or @CXX@ to g++-4.8 open the file: ~ns-2.35/linkstate/ls.h Change at the Line no 137  void eraseAll() { erase(baseMap::begin(), baseMap::end()); } to This void eraseAll() { this->erase(baseMap::begin(), baseMap::end()); } All changes ...

Simulation of URDF, Gazebo and Rviz | ROS Noetic Tutorial 8

Design a User-defined robot of your choice (or you can use the URDF file) and enable the LIDAR Scanner so that any obstacle placed on the path of the light scan will cut the light rays. Visualize the robot in the Gazebo workspace, and also show the demonstration in RViz.   (NB: Gain knowledge on wiring URDF file and .launch file for enabling any user-defined robot to get launched in the gazebo platform.) SLAM : One of the most popular applications of ROS is SLAM(Simultaneous Localization and Mapping). The objective of the SLAM in mobile robotics is to construct and update the map of an unexplored environment with the help of the available sensors attached to the robot which will be used for exploring. URDF: Unified Robotics Description Format, URDF, is an XML specification used in academia and industry to model multibody systems such as robotic manipulator arms for manufacturing assembly lines and animatronic robots for amusement parks. URDF is especially popular with users of the ...