This project is part of the ptp-sim project. See the ptp-sim project page for more information. There is also the ptp-sim discussion forum for further discussions.
This repository provides useful utilities to be used with the OMNeT++ network simulation framework.
This repository contains the following subprojects:
- Callable: Helper functions for classes that can be called directly from other classes.
- Channels: Additional channel definitions.
- DynamicSignals: Helper functions for registering signals during runtime.
- InitBase: Structured initialization of modules and subclasses of modules.
- ParameterParser: Helper functions to parse parameter strings to C++ enumerations.
In OMNeT++ modules usually communicate via message exchange.
But sometimes it is more suitable that modules directly call each other.
To support this, OMNeT++ provides the macros Enter_Method()
and Enter_Method_Silent()
.
But these methods only support the case when one module directly calls another module.
They do not support the case when one module would like to call a subclass of another module.
Consider the following pseudo-code:
clase A
{
public: void foo() {}; // <-- Can't call Enter_Method_Silent() here,
// as A does not inherit from cModule
}
class B: public cSimpleModule
{
public:
A a;
}
class C: public cSimpleModule
{
B *b;
C();
}
C::C()
{
b = check_and_cast<B *>(getModuleByPath("^.b"));
b->a.foo(); // <-- Directly calling a method from a child class of b
}
The Callable subproject provides helper functions to enable this scenario.
The Channels subproject provides additional channel definitions.
At the moment, it only provides a single channel: VolatileDelayChannel
.
This channel is meant to behave similar to OMNeT++'s own DelayChannel
, but
the delay parameter is volatile, and thus re-read on every access.
As a result, the delay of the channel can vary during the simulation run, instead of only being randomly selected at the beginning and then being constant for the rest of the simulation run.
OMNeT++ provides the possibility to register signals with dynamic names during runtime. The DynamicSignals subproject provides helper functions to make this a little bit easier.
OMNeT++ provides an API for structured initialization, by using the folloging functions:
numInitStages()
: returns the number of required calls toinitialize(stage)
initialize(stage)
: initializes the stage given by thestage
parameter
However, the tasks which are implemented in these stages are often the same for many different modules: parsing parameters, registering signals, etc. This results in similar, yet different code in multiple places.
To avoid code duplication and mistakes, it makes sense to introduce a common initialization approach.
This is what the InitBase subprojects does.
The interface class IInitBase
provides the following functions:
-
ParseResourceParameters(): Parse parameters that are required to allocate further resources.
-
AllocateResources(): Allocate required resources.
-
InitHierarchy(): Establish all needed parent-child relationships between this class and child classes (e.g. a child class might need a pointer to its parent class).
-
ParseParameters(): Parse all remaining configuration parameters.
-
RegisterSignals(): Register signals.
-
InitInternalState(): Initialize a consistent state for this module depending on the configuration.
-
InitSignals(): If the semantic of signals makes already sense on startup (e.g. the size of a queue could be 0 at startup), the initial signal values may be emitted here. After this stage it is allowed to use the module's signals.
-
FinishInit(): If the module needs to schedule events on startup or things like that, this should be done here.
-
PrintDebugOutput(): If the configuration tells the module to print initial debug output, this can be implemented here.
-
ForwardInit( int stage ): In case that this module has child classes that also implement the
IInitBase
interface,ForwardInit()
has to call theirinitialize(stage)
routine with its ownstage
parameter.IInitBase
takes care that child classes are only initialized after the parent process is ready.
The InitBase project provides the following helper classes:
- ModuleInitBase: this is for simple modules and directly inherits from
cSimpleModule
. - SubmoduleInitBase: the purpose of this class is to introduce the
IInitBase
interface to classes that are used as childs from other moduls that support the interface. The parent'sForwardInit()
function is responsible to call the child'sinitialize()
. On the other hand, the childs may rely on the parent for cSimpleModule-specific functions, like callingpar()
.
In case ModuleInitBase
or SubmoduleInitBase
are used, the following functions from the original OMNeT++ initialization API should not be used otherwise anymore:
- numInitStages()
- initialize( int stage )
Things are different if you would like to use IInitBase
with a class that already inherits from cSimpleModule
.
This can be the case if you extend modules provided by external libraries, like e.g. the INET library.
In this case you have to inherit from IInitBase
and make sure your implementations of numInitStages()
and initialize()
forward to the correct base classes.
Consider as an example the following pseudo code:
// Suppose this is a class from an external library, and you can't change it.
// You would like to inherit from it and use IInitBase.
class ExternalModule: public cSimpleModule
{
}
// This is your class
class MyModule: public ExternalModule, public IInitBase
{
}
int
MyModule::numInitStages() const
{
// Ensure we are called often enough
return std::max( IInitBase::numInitStages(), ExternalModule::numInitStages() );
}
void
MyModule::initialize(int stage)
{
// Forward initialize() calls to where they are needed
if( stage < ExternalModule::numInitStages() )
{
ExternalModule::initialize();
}
if( stage < IInitBase::numInitStages() )
{
IInitBase::initialize( stage );
}
}
This subproject helps to parse parameter strings into enumerations. This is done by providing a simple helper array for string/enumeration assignment and a stupid loop with element comparison. There is lots of room for improvement in the implementation of this subproject, but for now it works and does what it should :)
Pseudo code example:
// The enumeration you would like to use in your code
enum MyType
{
MY_TYPE_OPTION_A,
MY_TYPE_OPTION_B,
};
// A helper array to help assign strings -> enumerations
ParseType<MyType> MyTypeParseArray[] =
{
{ MY_TYPE_OPTION_A, "MY_TYPE_OPTION_A" },
{ MY_TYPE_OPTION_B, "MY_TYPE_OPTION_B" },
};
// Your custom parameter parsing class
class MyParser
{
public:
static MyType ParseMyType(const char *Str);
};
// Function to parse your enumerations
MyType
MyParser::ParseMyType(const char *Str)
{
return Parse<MyType>( MyTypeParseArray, ArrayLen(MyTypeParseArray), Str );
}
// Using the parser in your initialize routines (ParseParameters(), if you use InitBase):
MyType t = MyParser::ParseMyType( par( "MyTypeParameter" ).stringValue() );
See INSTALL.md for details.
This project is licensed under the 3-clause BSD license. See the LICENSE.txt file for details.
Please visit the ptp-sim discussion forum for further discussions.