VR-Link API Documentation for HLA 1.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Add Attribute example

This 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 FOM elements that we have added for this example are:

  1. Create a subclass of DtEntityStateRepository (myEsr.h.) with accessors for the new Mass attribute.
  2. Create a subclass of DtFireInteraction (myFireInter.h.) with accessors for the new Temperature parameter.
  3. Add mappings for the new attribute and parameter to the FOM Mapper, and tell the FOM Mapper to instantiate MyFireInteraction when an interaction of class WeaponFire is received. (For more information, please see configFomMap.h and configFomMap.cxx.)
  4. Tell DtReflectedEntity and DtEntityPublisher to use MyEntityStateRepository instead of the standard DtEntityStateRepository. (For more information, please see addAttr.cxx.)

The addAttr example is contained in the following files.

Using the New Classes

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.

/****************************************************************************
* Copyright (c) 2014 VT MAK
* All rights reserved.
****************************************************************************/
#include "myFireInter.h"
#include "myEsr.h"
#include "configFomMap.h"
#include <iostream>
// There are several places where you can configure a FOM Mapper to add an
// attribute. In this example, we create the DtExerciseConn with the default
// FOM Mapper, and then add attribute decoders, encoders and checkers after
// the DtExerciseConn constructor returns (using configFomMapper).
// Alternatively, we could have 1) created a subclass of DtRprFomMapper whose
// constructor registers the functions to deal with the new attribute, then 2)
// passed an instance of the new FOM Mapper subclass to the DtExerciseConn
// constructor.
// Callback function to be called when a Fire Interaction is received.
void fireCb(DtFireInteraction* inter, void*)
{
std::cout << "Received Fire Interaction!\n";
inter->printData();
std::cout << std::endl;
}
int main( int argc, char* argv[] )
{
// Used for error handling
DtINIT_MINIDUMPER( "addAttr" );
// Create a DtExerciseConn with FOM Mapper.
#ifdef DtHLA13
DtExerciseConn conn("example-vrlExtend", "addAttr", new DtRprFomMapper(0.8));
#else
//The FOM for 1516 is a little newer, so we use a different FOM Mapper
DtExerciseConn conn("example-vrlExtend", "addAttr", new DtRprFomMapper(1.0));
#endif
// Call configFomMapper to register functions to handle the new attribute
// and parameter.
configFomMapper(conn.fomMapper());
// Register the callback on incoming Fire Interactions.
DtFireInteraction::addCallback(&conn, fireCb, NULL);
// Tell reflected entity and entity publisher that they should create
// instances of MyEntityStateRep rather than the base
// DtEntityStateRepository to store state of objects.
// Create a reflected entity list
// Create an entity publisher
DtEntityPublisher pub(DtEntityType(1, 1, 225, 1, 1, 0, 0), &conn);
// We've told the publisher to use a MyEntityStateRep as its state
// repository, so this cast should be safe.
MyEntityStateRep* esr = (MyEntityStateRep*) pub.esr();
esr->setMass(215.0);
// Set essential attributes
// Middle of island in MAKland terrain
esr->setLocation(DtVector(3114872.406839,5449826.517832,1126516.629432));
esr->setOrientation(DtTaitBryan( 0.604654, 1.373067, 2.722311));
esr->setMarkingText(pub.objectId().string());
DtClock* clock = conn.clock();
while (1)
{
clock->setSimTime(clock->absRealTime());
conn.drainInput();
// Send a TestInteraction.
inter.setTemperature(150.0);
//conn.sendStamped(inter);
// Tick the publisher
pub.tick();
// Print the mass of the first entity in the list.
DtReflectedEntity* ent = rel.first();
if (ent)
{
// We've told DtReflectedEntity to use a MyEntityStateRep as its
// state repository, so this cast should be safe.
std::cout << "Current state of first entity.\n";
esr->printData();
std::cout << std::endl;
}
DtSleep(1.0);
}
return 0;
}

Document ID: Generated on Fri Dec 2 02:42:08 EST 2016 from SVN revision 171416
Copyright © 2005-2016 VT MÄK. All Rights Reserved (www.mak.com)