Before Getting Started
The tutorial will talk about using hla model for ns-3 to make ns-3 participate in distributed simulation with other federates through a Run Time infrastructure. The code for the tutorial can be found in .cc and .fed files. We will be referring to the ns-3 hla model Wiki, it has mostly model related explanation, only few sub-sections are required for the tutorial. Information about HLA and RTI. on Wikipedia.
The tutorial will assume that you have a working copy on ns-3 with hla which can be obtained here and familiarity with writing and running ns-3 scripts. Please download and install the required packages listed here as set the mentioned environment variables.
The objective here is to make a simple ns-3 script that publishes and subscribes to an object PingPong with attributes Msg and MsgType. Before we could start with this we need to send an initialisation message. Let us first look as what variable we have at our disposal, let's look at the initialisation variables and common terms:
- Seconds : Number of Times time advance request is expected.
- SyncPhase : The string that is used by federates for synchronisation in RTI.
- Fomfile : Name of the file that has the object model
- FederationName : Name of the federation (Should be same in all federates)
- FederateName : Name of the federate (ns3)
- RtiTimeResolution : What time steps are required by the model (Default is 1.0)
- Object Name : Name of the Object you are sharing
- Object Attributes : A property of the shared object
- Object Handle : Unique federate wide identifier for an object
- Attribute Handle : Unique federate wide identifier for the attribute
- Attribute Value : Value the attributes presently (RTI Time) posses
The above variables are used for initialisation. Ns-3 will create a federation <FederationName> or join the same if already created by other federates. It will register in the federation as federate <FederateName> and with a synchronisation phrase <SyncPhrase> and RTI will use the object model in <FomFileName>. The simulation will run for <Seconds>*<RtiTimeResolution> seconds and will advance in <RtiTimeResolutionSteps>. Hla model will take care of these events.
Now lets look at how the objects are created and published. After defining the object model in .fed file you have to create an object and attributes. You can create any number of objects (the helper uses a dynamic memory allocation) and add any number of attributes (again dynamic). You have to specify the name of the object and the number of attributes it will have. Once you create an object you are object handle is issued. This can used in future for listing all attributes of the object and accessing object name. Similarly, attributes can be added to object by specifying Attribute Name and Object Handle and it will return a similar Attribute Handle. All Objects are to be published and subscribed with the RTI. All events are taken care by the hla model
Synchronisation and Update
Whenever a time advance is required the hla model is designed to send it to the RTI and whenever the Time Advance Grant is approved it is handled by the hla model. For this functionality you have use a RTI simulator implementation. Whenever a value is changed in the RTI the hla model automatically updates the value in ns3, so the value of the shared object's attribute attribute value you are using is the one which is known to all federates and is in the federation. Again handled by the hla model.
More low-level implementation details of the hla model can be found here
The source code of the script can be found here. Functions from the src/hla/helper will be used here. It is good to have this file open along side in another tab. It has doxygen and thus you can easily figure out the API calls, we will be referring to it.
Using the hla API is quite intuitive and if you understand the concept it is quit straightforward. To begin with, you create an object of hla helper in your script:
Now set the initial values of the hla parameters as discussed above. Function in line number 74 sets the DefaultParameters similar to the example shipped with the code. You MUST set the values according to your requirements, your federation requirements and external federation requirements.For setting various values, just set them using various setter functions like on line 83,192,202,212,222,232. These are for initialization and there meanings are explained in the above section. For example:
hla.SetFomFile("SimpleSharedObjectExample.fed"); hla.SetSyncPhrase("ReadyToRun"); hla.FederationName("ExampleFederation"); hla.FederateName("ns3"); hla.SetRtiTimeResolution("1.0"); hla.SetSeconds("10"); or hla.DefaultParameters();
Once you are done setting you default values, you need to create an object that you can share, it can be easily done using function on line 95 :
int ObjectHandle; ObjectHandle = hla.CreateSharedObject("PingPong","2");
The above command creates a shared object "PingPong" and the object has two characteristics. It also returns an Object Handle (ObjectHandle) of int type used to identify the object. Next we need to set these characteristics or attributes, we can use function on line number 107 to so this:
int AttributeHandle1, AttributeHandle2; AttributeHandle1 = hla.AddAttributeOfSharedObject("Msg",ObjectHandle); AttributeHandle2 = hla.AddAttributeOfSharedObject("MsgType",ObjectHandle);
This will add two values "Msg" and "MsgType" to the Object "PingPong". Now we are done with the object and it's attribute. Let's publish it and create an ns3 Federate.
This will do the required, but before this we must change simulator implementation to RTI Simulator. This can be done using:
GlobalValue::Bind ("SimulatorImplementationType", StringValue ("ns3::RtiSimulatorImpl"));
So, now we are done with creating a federation, once the simulation start you can access values of the published object and other details related to the federation using the API functions at line 173,161,149,137,125 and 116. The values and time advance requests are handles by callbacks and simulator, so user does not have to specify anything for it. ns-3 will synchronise with the RTI and all values will be updated if anything changes in other federates.
Object Model file
The SimpleSharedObjectExample.fed was used for this tutorial. Please make sure you list all objects that you are using and their attributes in the .fed file in similar order. It is used by the RTI. Please note that you have to include these three lines at the beginning. This is because the Portico FED parser want it to be like this.
(FED (Federation Portico-Test) (FEDversion v1.3) ... ... )
List all your objects under the ObjectRoot class, this is done basically to encapsulate all shared Object (classes) created by ns-3 into ObjectRoot class and add attributes as follows. The basic structure of the file should be like this:
(objects (class ObjectRoot (class ... (attribute ...) (attribute ...) (class ... (attribute ...) (attribute ...) ..... ..... ) ) )
Please refer to portico documentation for more details on the .fed files.
Once you have created your .cc and .fed file you can easily run the simulation according to instructions here. So, as it is clear from the section, we will look deeper into the three commands:
$ ./hla.sh --clean $ Cleaning log files and jar
It will clear all your files that are generated using your java code. This will include .class files and .jar files. It will also clear all log files. These log files are created by the Run Time Interface, in this case portico. The files can be found in $build/src/hla/model/ns3Federate. It will log the following message
$ ./hla.sh --build $ Building HLA interfaces
It will compile hla module code written in java and will save it in $build/src/hla/model/ns3Federate. Make sure you build ns-3 first by using ./waf, before building hla. To run a specific simulation you can use.
$ ./hla.sh --run scratch/SimpleSharedObjectExample
Make sure you copied your .fed to $ns/scratch and also you are using the .fed file name in the --run command. Also please follow the sequence in which you start the two shells as given in the Wiki Instructions
The first way to test the code is run two shells one with simple-shared-object-example.cc (in shell 1, say CppShell) and SimpleSharedObjectExample.fed( in shell 2, say JavaShell) as mentioned above. The following will be observed:
in Cpp Shell, if sockets are initialised properly you will get:
***** Ready To Connect To RTI and launch/join Federation Connecting ...
now start the JavaShell and now run the code using ./hla.sh (as mentioned in the above section)in the other shell, If your fed file is in the right place and the sockets are initialised properly you will get:
Connected ... Receiving Initialization Message .. Setting Initial Values ... ns3 : >>>>>>>>>> Press Enter to Connect To RTI <<<<<<<<<<
It also confirms that your values were received through the socket and received by the Java Program (Initial Values). This is a good time(***) to launch other federates
and the CppShell will show:
Connected Sending intialization message Waiting for Start Signal..
when you press enter### once in JavaShell it will:
ns3 : Connecting ... ns3 : Connected ns3 : Created Federation ns3 : Joined Federation as ns3 ns3 : >>>>>>>>>> Press Enter to Continue <<<<<<<<<<
connect to the RTI and when you press enter again it will send a start signal to CppShell. It checks if ns3 Federate is able to create and join a federation or not. It will start the simulation and if the RTI time>ns3Time it will process all events
Start Signal Received Present Time (in ns): 0 Event Time Missed, Ns3 Time More Than RTI Time Processing Event ...
and the output of the event is displayed. If RTI Time<ns3Time it will ask the event to wait and send a time advance request.
Present Time (in ns): 1000000000 Event in Future, Ns3 Time Less Than RTI Time Wait For a Time Advance Signal from RTI ... Sending Time Advance Request to RTI ... Time Advance Request Sent Time Advance Granted
Once the request is grated it will execute the event and the event specific log will be displayed. If there is a change in the object values, a callback will log the following:
Value of Shared Object (any attribute) changed ... Updating ... Updated
At time (***) is the best time to start an external federate. There is an external federate along with the code in test/SystemIntegration, although there is an issue which might pop up at present (related to RTI) but if no it can be started at time (***) in another shell, lets call it external
external$ cd $ns3/src/hla/test/SystemIntegration/dummy external$ ./linux.sh execute
It should start the federate. After a bit of logging it will ask you to press
dummy : >>>>>>>>>> Press Enter to Connect To RTI <<<<<<<<<<
when you press enter it will wait for other federates (like ns3) and when we press enter in step (###), we will force ns3 to join the federation
Registered Sync Point, waiting for federation ...
and in the $JavaShell
ns3 : Connecting ... ns3 : Connected ns3 : Cannot create federation, federation already exists ns3 : Joining Federation as ns3
Now the ns3 and dummy federates will be synchronised. Dummy will change the value of PinPong every second and will be reflected on $CppShell and $JavaShell