Migrating your INET-based models from OMNeT++ 3.x to 4.x
========================================================

Overview
========
The tools in this directory are for migrating simulation models based
on previous INET versions, written for OMNeT++ 3.x. These tools
should be run *after* the corresponding migration scripts in OMNeT++
(omnetpp-4.x/migrate/*).

What has changed in INET for OMNeT++ 4.x?

 - most differences are due to OMNeT++ changes: different NED and ini file
   syntax, C++ code changes due to simulation library changes (64-bit
   simtime, added "get" verbs, methods renamed, etc)

 - directory structure. Now everything is under src/ and examples/.

 - NED:
   - several parameters and gates got renamed (as we standardized on
     camelCaseNames instead of under_score_names; also gate names are
     now xxxIn/xxxOut versus the old fromXxx/toXxx to from_xxx/to_xxx)

   - default values and @units added to many parameters

   - "in"+"out" gates of Router/StandardHost got merged to inout gate "pppg",
     and corresponding pairs of unidirectional connections got merged
     into single bidirectional ones

   - likewise, "ethIn"+"ethOut" gates and connections got merged into
     "ethg" ones

   - wherever "like" occurred in NED files, a module interface got
     extracted, and the modules implement that interface; for example,
     all mobility models now implement "IMobility" (by convention, names
     of module interfaces begin with "I")

   - other smaller changes

 - msg:
   - removed omitGetVerb everywhere - now all getter methods begin with "get"

 - C++:
   - several methods and some classes got renamed, mostly to let getter
     methods begin with the word "get"

Prerequisites:
==============

 - read Migration.pdf from the OMNeT++ 4.0 distro. You ABSOLUTELY want
   to do that before doing anything.

 - make sure you have a *backup* of the original source files you
   want to port. If you have your sources in a version control
   system (like Subversion, Mercurial or Git; highly recommended!)
   make a branch or at least a different working copy.

 - have a good visual diff tool at hand that can also compare whole
   directory trees (like meld, winmerge, k3diff, etc).

The migration process
=====================

A generic advice beforehand: don't try to swallow everything at once.
Do the porting with simtime_t = double first, get everything working,
validate if possible -- THEN switch to int64-base simtime.

1. Project Setup.

If you extended INET, it's likely that your sources are in various
subdirs in the INET directory tree. In OMNeT++ 4.0 it is possible to
do it in a cleaner way, by separating the base INET and you project
into two separate projects. It goes like this:

   1. Start the IDE.

   2. Import the base INET as a project (File|Import... --> General /
      Existing projects into workspace)

   3. Create a new OMNeT++ project, and copy your sources into it.
      (We recommend you make a "src" and an "examples" or "simulations"
      subdirectory.)

   4. Mark you project as dependent on INET (Project Properties --> Project
      References --> check INET).

Then your project can use modules from INET, your C++ sources may include
headers from INET etc, all automatically. No manual tweaking needed.

This setup also has the advantage that when a new INET version comes out,
you can just replace your INET dir with the new one; no manual merging
needed.

2. Switch OMNeT++ to "double" simtime

Add -DUSE_DOUBLE_SIMTIME to CFLAGS (CFLAGS_DEBUG and CFLAGS_RELEASE)
in Makefile.inc or configure.user, whichever you like (in the latter case
don't forget to re-run ./configure), or by temporarily adding
#define USE_DOUBLE_SIMTIME to the top of include/simkerneldefs.h;
then recompile it (make cleanall; make)


3. Run migration scripts

Much of the migration process is automated by various scripts, located under
omnetpp-4.x/migrate and INET/migrate. They should be run on the command prompt
(not inside IDE).

  a. make copy of the current state of your sources

  b. run the scripts one by one, first the OMNeT++ ones, then the INET ones.
     The scripts convert files in the current directory, so you need to
     "cd" to your project's root dir, and invoke the scripts from there,
     like:
         $ cd ~/workspace/myproj
         $ ~/omnetpp-4.0/migrate/migratened

     With migratecpp, you also want to save the output into a text file, as
     it prints various suggestions about the source.

   c. start your visual diff tool (meld etc), and diff the project to the
      backup you did in step (a), to review what changes the scripts did.
      Most migration scripts work by plain text substitution (basically
      global find/replace), and occasionally they replace things they were
      not supposed to.


4. NED files

The migration scripts only do part of the job. You need to do some more manual
changes to get error-free NED files; and you'll probably want to make further
changes, to make use of the new possibilities of NED.

Revise module parameters

  Especially simple module parameters. Many that came out as "double" or
  "volatile double" after the migration script should actually be "int" or
  "volatile int". (In 3.x there was only a "numeric" type, and the migration
  script of course doesn't know whether they should be "int" or "double" now.)
  Example:
     volatile double numHosts;   // should be: int numHosts;

  You can now provide default values to parameters, so that they can be
  simply assigned in omnetpp.ini, with **.apply-default = true.

  Also, some parameters need units. Like those that are time should have
  @unit(s), packet length etc in bytes should have @unit(byte) or @unit(B),
  etc.  Units should be added to values and default values too.
  Examples:
     double timeout;
     double startTime;
     volatile double sendInterval;
  could be changed to:
     double timeout @unit(s) = default(120s);
     double startTime @unit(s) = default(uniform(1s,2s));
     volatile double sendInterval @unit(s) = default(exponential(100ms));

  By convention, parameter names begin with lowercase, and use camelCase
  instead of under_scores.

Adjust gate names

   To be more compliant with the new INET naming convention, you may change
   gate names to the style xxxIn/xxxOut, from the former from_xxx/to_xxx or
   fromXxxx/toXxxx.

Merge gates of routers/hosts

   If you have host or router models, change their gates like this:
        inout in[];
        output out[];
        input ethIn[];
        output ethOut[];
   to:
        inout pppg[];
        inout ethg[];

   Merge the corresponding connections too, like:
        in[i] --> ppp[i].physIn;
        out[i] <-- ppp[i].physOut;
   needs to be changed to:
        pppg[i] <--> ppp[i].phys;

   And this:
        ethIn[i] --> eth[i].physIn;
        ethOut[i] <-- eth[i].physOut;
   to
        ethg[i] <--> eth[i].phys;

   And of course sizeof(ethOut) changes to sizeof(ethg), and sizeof(out)
   to sizeof(pppg).

Use bidirectional connections

   Merge pairs of uni-directional connections to a single bidirectional one;
   for example, this:
        r1.out++ --> ethernetline --> r2.in++;
        r1.in++ <-- ethernetline <-- r2.out++;
   becomes
        r1.pppg++ <--> ethernetline <--> r2.pppg++;
   You also can use the provided "mergenedconns" migration script to
   automate this step. Review the results though.

Fix channel datarates

   Channel data rates used to be plain numbers; now it expects a unit
   like Kbps or Mbps. Change likes like:
         datarate = 512*1000000;
   to
         datarate = 512Mbps;

Make channels inner types

   It was customary to put channel definitions in the same file as your
   network. These channes can now become inner types of the network.
   That is, a channel like
        channel fiberline extends ned.BasicChannel
        {
            parameters:
                delay = 1us;
                datarate = 512Mbps;
        }
   may be moved inside the network:
        network MyNetwork
        {
            parameters: ...
            gates: ...
            types:
                channel fiberline extends ned.BasicChannel {
                    delay = 1us;
                    datarate = 512Mbps;
                }
             submodules: ...
             ...
        }

Eliminate superfluous network definitions.

   After conversion, you're going to see NED code like:
       module MyNetwork
       {
           // submodules, connections etc...
       }

       network myNetwork extends MyNetwork
       {
       }
   Which can be simplified to:
       network MyNetwork
       {
       }
   Remember to change "myNetwork" to "MyNetwork" in the corresponding ini file,
   too!

Add/make use of default icons.

   Add default icons to your simple modules. Looks like this:
       simple MyModule {
           parameters:
               @display("i=block/table");
               ...
       }
   The modules in INET have default icons now too, so after this you can safely
   kill off almost all "i=" stuff can be killed off from submodule display strings
   in compound modules and networks.

FlatNetworkConfigurator changes

   In the new INET, FlatNetworkConfigurator no longer has the parameters
   "moduleTypes" and "nonIPModuleTypes"; so these parameters can be removed
   from the NED files. Instead, all module types that represent some physical
   device in the network have to be annotated with @node(): hosts, routers,
   switches, access points, etc. Example:

       module Router
       {
           parameters:
               @node();   <==== note added property!
               string routingFile = default("");
           //...
       }

   If you wrote your own Configurator, you'll probably want to revise it as well,
   and use topo.extractByProperty("node") instead of extractByModuleType(..).
   Existing extractByModuleType(..) calls probably won't work out of the box
   anyway, because NED type names need to be referred to with fully qualified
   name, that is, "inet.nodes.inet.StandardHost" instead of just "StandardHost".
   The same for findModuleType(): they'll only work if you write fully qualified
   names.


5. C++ files


6. ini files


7. Validate

Run your simulations and make sure they do what they are supposed to do.
Possibly, compare output or saved log with that from the original (3.x)
version.


8. Recompile with int64-based simtime_t

Change back OMNeT++ to int64-based simtime_t (basically undo what you did
in (2)); then recompile everything. In your project you'll encounter
lots of "cannot convert simtime_t to double" and "no matching function for
somethingOrOther(foo_t, bar_t, const simtime&)". The solution is usually
one of these:
  - change variable or function argument from "double" to "simtime_t"
  - add an explicit cast to double (SIMTIME_DBL() macro)
It is sometimes tricky which way to choose, but you'll get the hang of it
after a while.


9. Validate

Run your simulations again, and make sure they work correctly. You cannot
expect to get the exact same output as from "double" simtime, due to increased
precision of simtime; outputs may even diverge significantly after a while,
as the simulation chooses a differen trajectory; but still try to make sure
things work correctly.


10. Rejoice

Release a big sigh of relief, and go out to have a beer :)


Send questions, problems, hatemail to:
andras@omnetpp.org


