![]() |
VR-Link API Documentation for HLA Evolved
|
The Add Attribute example demonstrates how to extend the RPR FOM by adding new attributes or parameters to existing classes, particularly when this requires extending VR-Link's API to work with them. It creates an executable that works with the example-VrlExtend.fed FED file that is in the VR-Link root directory.
The code in the addAttr example explains the steps you need to take when you add a new attribute or parameter to existing classes in your FOM. In this example, we assume that the new attribute and parameter represent concepts not present in the VR-Link top-level API. Therefore, we must first extend the API to provide accessors for the new concepts, then configure the FOM Mapper so that it can map between the new FOM elements and the API extensions.
The following FOM elements that we have added for this example are in the file VrlExtend.fed:
To work with these additions do the following:
We extend the DtEntityStateRepository in MyEntityStateRep and declare and define an entity state repository that adds the attribute "Mass" to the existing DtEntityStateRepository.
Applications typically get state information about entities from a DtEntityStateRepository. This class has mutators and inspectors that provide access to many components of an entity's state, but the concept of mass is not one of these components. So in the file myEsr.h, we extend the DtEntityStateRepository API by deriving a class called MyEntityStateRep.
We added an inspector and mutator function for the concept of mass, and overrode the virtual printData() function, so that mass will be printed along with the other state data. Finally, we provided a static create() function that you can register with other VR-Link classes, so that they can create an instance of our new state repository. These functions have straightforward implementations.
In myFireInter.h, we extend the API provided by the DtFireInteraction class, to add accessor functions for the concept of temperature. Again, we override printData(), and provide a static create() function.
We need to provide code that can map between the FOM attribute and parameter, and our API extensions. This code is in configFomMap.cxx. The function configFomMapper() takes a pointer to a FOM Mapper as an argument and configures that FOM Mapper so that it contains our new mappings. The assumption is that the FOM Mapper that will be passed to us already contains the standard RPR FOM mappings, so that we only need to add our new mappings. We do not have to worry about adding mappings for the rest of the FOM.
In configFomMapper(), listed below, we first register our MyFireInteraction class's create function with the FOM Mapper's interaction factory, so that it knows that this is the DtInteraction subclass that it should instantiate to represent incoming interactions of the FOM class WeaponFire. We do not need to do anything similar for objects here, but we will see later that we need to tell our DtEntityPublisher and DtReflectedEntity classes that they should be using our MyEntityStateRepository class to store the state of the objects that they represent.
The rest of configFomMapper() shows the registration of encoding, decoding, and checking functions for our new attribute and parameter. Decoding functions take data from FOM representation, and pass it to interaction or state repository mutator functions (after performing any necessary format conversions.) Encoding functions obtain data using interaction or state repository inspector functions, and add them to outgoing state updates in FOM representation (again after performing any necessary conversions.) Checking functions check whether an attribute's update condition has been met, usually by comparing the data in a current state repository, and a state repository that represents the state that would be seen by remote federates based on updates that we have sent.
The functions use VR-Link's "Net" types, so byte swapping occurs automatically during conversions to and from native types.
In addAttr.cxx, we construct a DtExerciseConn, telling it to use our modified FED file, VrlExtend.fed. By not passing a DtFomMapper argument, we are indicating that the default RPR FOM FOM Mapper should be used:
After the DtExerciseConn is created, we pass its FOM Mapper to the configFomMapper() function that we wrote in configFomMap.cxx. This adds our new mappings:
The application uses these classes and functions to send and receive the entities and fire interactions with the new attributes (mass for entities and temperature for fire). Running two instances of addAttr demonstrates that the new attributes are sent and received.
To get our DtEntityStateRepository extensions plugged into VR-Link, we tell the DtReflectedEntity and DtEntityPublisher classes that they should use instances of MyEntityStateRepository, rather than the default DtEntityStateRepository, to store their objects' state. We do this by using those classes' static member function setStateRepCreator().
Later, when we create a DtEntityPublisher to manage sending updates for a locally simulated entity, we can cast the state repository returned by its esr() function to a MyEntityStateRepository, and use its setMass() function to set the entity's mass.
On the receiving side, we can cast a DtReflectedEntity's state repository to a MyEntityStateRepository as well, and inspect the entity's mass using its mass() member. In the example, we just call its printData() virtual function, for which the cast is not really necessary.
To send a fire interaction that includes our temperature parameter, create an instance of MyFireInteraction, set the temperature, and send it.
To receive it, register a callback function with DtFireInteraction.
Within the callback, we can cast the DtFireInteraction pointer to a pointer to MyFireInteraction, and inspect the temperature using its temperature() member, or just use its virtual printData() function, which should print the temperature along with the other parameters.
In this example, we did not provide static addCallback() and removeCallback() functions in the MyFireInteraction class, as most VR-Link interaction classes do. Had we done so, they would have allowed callback functions that take a MyFireInteraction pointer rather than a DtFireInteraction pointer. If we were able to use such specific callbacks, we could avoid a cast to MyFireInteraction within the callback, which is otherwise necessary to inspect subclass-specific data.
After you build the addAttr example, run two copies of it. You should see them communicating with each other. Each should print state and interaction information received from the other, including values for the new attribute and parameter.
The addAttr example is contained in the following files.
This file contains the class declaration and definition of an entity state repository that adds the attribute "Mass" to the existing DtEntityStateRepository.
This file contains the encoder, decoder, and checker functions to properly send the "Mass" and "Temperature" attributes across the network. It also contains a function that configures the FOM Mapper to use these functions.