We have the methods and mechanisms for establishing OTcl Linkage earlier Chapterchap:otcl:intro. This section is a brief review of the essential features of that earlier chapter, and describes the minimum functionality required to create the ping agent.
There are three items we must handle to properly link our agent with Otcl. First we need to establish a mapping between the OTcl name for our class and the actual object created when an instantiation of the class is requested in OTcl. This is done as follows:
static class ECHOClass : public TclClass { public: ECHOClass() : TclClass("Agent/ECHO") {} TclObject* create(int argc, const char*const* argv) { return (new ECHO_Agent()); } } class_echo;Here, a static object ``class_echo'' is created. It's constructor (executed immediately when the simulator is executed) places the class name ``Agent/ECHO'' into the OTcl name space. The mixing of case is by convention; recall from Section 3.5 in the earlier chapters that the ``/'' character is a hierarchy delimiter for the interpreted hierarchy. The definition of the []create method specifies how a C++ shadow object should be created when the OTcl interpreter is instructed to create an object of class ``Agent/ECHO''. In this case, a dynamically-allocated object is returned. This is the normal way new C++ shadow objects are created.
Once we have the object creation set up, we will want to link C++ member variables with corresponding variables in the OTcl nname space, so that accesses to OTcl variables are actually backed by member variables in C++. Assume we would like OTcl to be able to adjust the sending interval and the packet size. This is accomplished in the class's constructor:
ECHO_Agent::ECHO_Agent() : Agent(PT_ECHO) { bind_time("interval_", &interval_); bind("packetSize_", &size_); }Here, the C++ variables interval_ and size_ are linked to the OTcl instance variables interval_ and packetSize_, respectively. Any read or modify operation to the Otcl variables will result in a corresponding access to the underlying C++ variables. The details of the []bind methods are described elsewhere Sectionsec:VarBinds. The defined constant PT_ECHO is passed to the []Agent constuctor so that the []Agent::allocpkt method may set the packet type field used by the trace support Sectionsec:traceptype. In this case, PT_ECHO represents a new packet type and must be defined in trace.h Sectionsec:traceformat.
Once object creation and variable binding is set up, we may want to create methods implemented in C++ but which can be invoked from OTclSectionsec:Commands. These are often control functions that initiate, terminate or modify behavior. In our present example, we may wish to be able to start the ping query agent from OTcl using a ``start'' directive. This may be implemented as follows:
int ECHO_Agent::command(int argc, const char*const* argv) { if (argc == 2) { if (strcmp(argv[1], "start") == 0) { timeout(0); return (TCL_OK); } } return (Agent::command(argc, argv)); }Here, the []start method available to OTcl simply calls the C++ member function []timeout which initiates the first packet generation and schedules the next. Note this class is so simple it does not even include a way to be stopped.