VR-Link API Documentation for HLA 1.3
4.3 - Working with Interactions

Table of Contents

Within VR-Link, we use the term interaction to refer to the data that is exchanged among simulation applications in an exercise to describe events, such as the firing of a munition, detonation of a munition, or collision of entities.

While the term is from HLA (rather than DIS), we use it in a protocol-independent sense to refer to an HLA interaction or a DIS PDU that describes an event.

Each type of interaction has its own class, for example, fire, detonate, and collision interactions are represented by DtFireInteraction, DtDetonationInteraction, and DtCollisionInteraction respectively. For both DIS and HLA, the individual interaction classes are derived from DtInteraction. DtInteraction is defined in hInteraction.h (HLA) and dInteraction.h (DIS). If you include interaction.h, an appropriate version is included.

VR-Link has protocol-specific versions of each of the interaction classes. Although the protocol-specific versions of these classes are defined separately, most of the public member function names and signatures are used in both versions, so you can use most of them in the same way, regardless of whether you are using DIS or HLA.

A similar naming scheme exists for individual interaction classes and their header files. The following table lists some interaction classes and their associated header files for HLA, DIS, and protocol-independent programming. The protocol-independent header files include the appropriate version of each class for the protocol for which you are building.

Interaction Class Header File Naming Conventions
Interaction HLA DIS Protocol-independent
DtFireInteraction hFireInter.h firePdu.h fireInter.h
DtDetonationInteraction hDetInter.h detonatePdu.h detonateInter.h
DtCollisionInteraction hCollideInter.h collidePdu.h collideInter.h

For DIS applications, DtFireInteraction, DtDetonationInteraction, DtCollisionInteraction, and so on are equivalent to DtFirePdu, DtDetonationPdu, and DtCollisionPdu. That is, we typedef one to the other. You can use the DtPdu class names if your application is only for DIS. However, you must use the DtInteraction names if you are writing code for both DIS and HLA, and this is what we recommend.

In DIS, DtInteraction is derived from DtPdu. The DtInteraction class itself has no real functionality, but the extra level gives our class hierarchy some structure. For example, DtFirePdus are (and can be implicitly cast to) DtInteractions and DtPdus. Entity state PDUs are not interactions, and thus DtEntityStatePdu is derived directly from DtPdu, not from DtInteraction.

4.3.1 Sending Interactions

To send interactions:

  1. Create an instance of the appropriate interaction class (derived from DtInteraction).
  2. Use its mutator functions to set values for the different parameters.
  3. Send it using DtExerciseConn's sendStamped() function.

The following code shows how to create and send a fire interaction, which informs the exercise that you have fired a munition. The example assumes that myId, targetId, and missileId are existing objects.

DtExerciseConn exerciseConn(...);
...
// Create a DtFireInteraction
DtFireInteraction fireInter;
// Fill the DtFireInteraction with data
fireInter.setAttackerID(myId);
fireInter.setTargetID(targetId);
fireInter.setMunitionId(missileId);
fireInter.setEventId(exerciseConn.nextEventId());
...
// Send to the exercise
exerciseConn.sendStamped(fireInter);

In both DIS and HLA, sendStamped() includes a time stamp with outgoing interactions. Because this is usually desired, we recommend that you use sendStamped() to send interactions, rather then send().

The value used for the time stamp is the value returned by DtExerciseConn's currentTimeForStamping() function. By default, this function returns the current value of the system clock when using relative timestamping, or the current value of VR-Link simulation time when using absolute timestamping. If you want sendStamped() to compute timestamps for outgoing messages differently, you can subclass DtExerciseConn and override currentTimeForStamping(). Timestamps are marked as either "relative" or "absolute" depending on the DtExerciseConn's current time stamp type. For more information, please see 2.7.6 Timestamps.

For a description of the mutator functions for a particular interaction class, please see the appropriate header files.

For DIS, sendStamped() also puts the DtExerciseConn's exercise ID into the header of outgoing PDUs.

4.3.2 Receiving Interactions

Incoming interactions are handled through interaction callbacks. For more information about callbacks, please see 2.7.3 Using Callbacks.

Application developers write and register callback functions for a particular interaction type with VR-Link, and VR-Link calls those functions when it receives an interaction of that type from within DtExerciseConn::drainInput(). The received interaction is passed to the callback function, allowing you to process the interaction as it arrives.

Each interaction class has the static member functions addCallback() and removeCallback(). These functions allow you to register and unregister your callback functions for particular interaction classes.

There is a different callback function type for each interaction class. For example, only callback functions that take a DtFireInteraction pointer as an argument can be registered with the DtFireInteraction class. A DtFireInteraction callback might look like this:

void myFireCallback(DtFireInteraction* inter, void* usr)
{
std::cout << "Got a Fire Interaction from " <<
inter->attackerId().string()<< std::endl;
}

It would be registered with VR-Link's DtInteraction class like this:

DtFireInteraction::addCallback(exerciseConn, myFireCallback, NULL);
Note
Since addCallback() is a static member of DtFireInteraction, it can be called using the qualified name, rather than calling it on a particular instance of DtFireInteraction.

The value passed to your callback function as usr is the value that was passed as the usr argument to addCallback(). Often, this usr argument passes a pointer to an object on which you want to call a member function from within your callback. Simply cast usr back to the object's type within the callback. For examples of passing objects through the usr pointer, please see 2.7.3 Using Callbacks.

When an interaction is received for which there are multiple callbacks registered, the callbacks are called in the opposite order from that in which they were registered.

Note
DtInteractions are transient, that is, they are deleted by VR-Link immediately after the last callback function registered for the interaction is called. Therefore, do not attempt to delete or save a pointer to the DtInteraction passed to your callback function. If you need to save the data, make a copy of the DtInteraction.

4.3.2.1 Making RTI Calls in Response to Interactions

In HLA applications, interaction callbacks are called from within RTI::tick() (which is called by DtExerciseConn::drainInput()). Some RTIs do not allow calls to RTI services from within other RTI service calls (including RTI::tick()). This means that you cannot directly or indirectly make any RTI calls from within your interaction callbacks.

If you need to make RTI calls based on the receipt of a DtInteraction, in your interaction callback, use DtExerciseConn::addPostDrainCallback() to register a function with VR-Link. It will get executed right before drainInput() returns, when it is safe to make RTI calls.

For example, the following code will ensure that your application sends out a fire interaction each time it receives a fire interaction:

void sendFire(void *usr)
{
// Cast the usr pointer back to a DtExerciseConn
DtExerciseConn* exConn = static_cast<DtExerciseConn*>(usr);
// Create and send a DtFireInteraction
DtFireInteraction fireInter;
fireInter.setAttackerId(...);
...
exConn->sendStamped(fireInter);
// Remember to deregister ourselves, so that we don't
// get called again the next time drainInput is called.
exConn->removePostDrainCallback(sendFire, exConn);
}
void fireCb(DtFireInteraction* inter, void *usr)
{
// Cast the usr pointer back to a DtExerciseConn
DtExerciseConn* exConn = static_cast<DtExerciseConn*>(usr);
// Can't send a fire interaction here, since that
// would involve an RTI call from within an RTI-service
// callback. So instead, register a fire-sending
// function (sendFire) as a postDrainCallback.
exConn->addPostDrainCallback(sendFire, exConn);
}
main()
{
DtExerciseConn exerciseConn(...);
...
// Register fireCb as a fireInteraction callback,
// passing a pointer to the DtExerciseConn as the usr
// pointer, so that it will be available to us within
// the callback.
DtFireInteraction::addCallback(&exerciseConn, fireCb,
&exerciseConn);
...
}

For more information, please see 4.2.4.3 Post-Drain Callbacks.

[<< Connecting to Exercises] [Home] [Top of Page] [Working with Entities >>]


Document ID: Generated on Wed Aug 14 15:35:11 EDT 2013 from SVN revision 130445
Copyright © 2005-2013 VT MÄK. All Rights Reserved (www.mak.com)