VR-Link JAVA API Documentation
 All Classes Namespaces Files Functions Variables Enumerator Pages
5.5 - Managing HLA Objects

Table of Contents

VR-Link uses instances of the DtHlaObject class (defined in hlaObject.h) to represent both local and reflected HLA objects.

Because most entity management functionality is available through VR-Link's protocol-independent layer, most applications do not need to interact with DtHlaObjects (or even know they exist). However, there are always DtHlaObjects behind the scenes.

On the outgoing side, a DtObjectPublisher creates and uses a DtHlaObject to help with the sending of attribute updates. On the incoming side, VR-Link creates a DtHlaObject instance for each object that we discover through the RTI. If the object is to be managed by a DtReflectedObject, then that DtReflectedObject stores a pointer to its DtHlaObject, and uses it to help manage the receipt of incoming attribute updates.

Both DtReflectedObject and DtObjectPublisher have an hlaObject() member function that returns a pointer to the DtHlaObjectWithStateRep that it is managing.

VR-Link maintains a list of all reflected and locally simulated HLA objects, without regard to what kind of reflected object or object publisher is being used to manage the objects (if any). This list is accessible through the DtHlaObjectManager class (defined in hlaObjectManager.h). An instance of this class is created by DtExerciseConn, and is available through DtExerciseConn's hlaObjectManager() function.

The HLA object manager class has a function called allHlaObjects(), which returns a DtList of pointers to all current reflected or local DtHlaObjects. The list is automatically updated whenever a new object is discovered or removed by an RTI-initiated service invocation, or when you create a DtHlaObject to represent a locally simulated object (which happens when you create a DtObjectPublisher).

For example, to print the IDs of all objects currently being simulated:

#include <vl/rtiCompatibility.h>
DtExerciseConn exConn(...);
...
// Subscribe to various object classes, process discoverObjects and
// reflectAttributeValues calls. (This is usually achieved simply by
// creating a DtReflectedObjectList.)
...
DtHlaObjectManager* objMgr = exConn.hlaObjectManager();
const DtList& allObjects = objMgr->allHlaObjects();
for (DtListItem* item = allObjects.first(); item;
item = item->next())
{
// Cast the generic void* to a DtHlaObject*
DtHlaObject* obj = (DtHlaObject*) item->data();
std::cout << "id: " << obj->objectId() << std::endl;
}

The HLA manager class also lets you look up HLA objects by ID or by name, using their hlaObject() member functions. These functions return NULL if no object with the given ID exists. It also gives you the list of all registered hlaObjects (those created by publishers and, hence, locally simulated) and the list of all discovered objects (remotely simulated) using the registerObjects() and discoveredObjects() functions. These functions return lists of pointers to DtHlaObjects.

In addition to the functions that give basic information about an HLA object (objectId(), name(), classDesc()), DtHlaObject has member functions that allow you to obtain more specialized information. The following table describes these functions:

Additional DtHlaObject Member Functions
Function Description
attributesNeededByFederation() Returns the set of attributes of this object that have been subscribed to by remote federates, as told to us by the RTI.
classNeededByFederation() Tells you whether the class has been subscribed to at all by remote federates.
requestedAttributes() Returns the set of attributes for which updates have been requested by another federate through the RTI, since the time that we last sent updates for those attributes.
lastSimTimeUpdateReceived() Returns the time that the last attribute update was received for this object, if it is a reflected object.

5.5.1 Finding Out when HLA Objects are Discovered and Removed

4.6.7 Learning when Entities Join or Leave an Exercise, describes protocol-independent methods of receiving notification about the discovery and removal of reflected objects. These methods involved either registering "objectAddition" and "objectRemoval" callbacks with a DtReflectedObjectList, or deriving from a subclass of DtReflectedObjectList and providing new definitions for the objectAdded() and removeAndDelete() virtual functions.

Although these are the preferred methods (due to protocol-independence, and ability to access the DtReflectedObject associated with an object), this section describes another method, which works at the level of DtHlaObject. By using this method, you can be notified when any HLA object joins or leaves, rather than just one particular kind of object (entities, for example).

When a new object is discovered, the DtExerciseConn creates a DtHlaObject to represent it, and adds it to the DtReflectedObjectManager's list of all reflected HLA objects. It is then passed to any "discoverObject" callback functions that have been registered with the DtExerciseConn for the object's class. You can register discoverObject callback functions for any object class using DtExerciseConn's addDiscoverObjectCallback() member function. Callbacks can be unregistered using removeDiscoverObjectCallback().

In RTI 1.3, if you want to be notified when any object is discovered regardless of class, use:

addDiscoverObjectCallback(RTI::ObjectClassHandle(0));

In RTI 1516, if you want to be notified when any object is discovered regardless of class, use:

addDiscoverObjectCallback(RTI::ObjectClassHandle());

Callback functions that you provide should match the signature defined in discoverObjectCbInfo.h, for example:

void myDiscoverObjectCb(DtHlaObject* obj, void* usr);

If you want to be notified when an object is removed, you can use DtHlaObject::addRemoveObjectCb() to register a removal callback directly with the DtHlaObject of interest. Such functions can be unregistered with removeRemoveObjectCb().

Alternatively, you can use DtExerciseConn's addRemoveObjectCallback() and removeRemoveObjectCallback(), in which case you need to pass an object ID to specify which object you are interested in.

In either case, your callback functions should match the signature defined in removeObjectCbInfo.h. For example:

void myRemoveObjectCb(DtHlaObject* obj, void* usr);

When the removeObject() service is invoked by the RTI, the corresponding DtHlaObject is:

  1. Removed from VR-Link's internal list of reflected HLA objects.
  2. Passed to any callback functions registered on the removal of the object.
  3. Deleted.

For instance, these callback mechanisms are the mechanism by which DtReflectedObjectLists are notified of the arrival and removal of reflected objects. When the reflected object list's discoverObject() callback is invoked, it creates a new instance of the appropriate DtReflectedObject subclass to manage the object. When its removeObject() callback is invoked (reflected object lists register one for each object as it is discovered), the DtReflectedObject is removed from the list and deleted.

5.5.2 Intercepting Reflected Attribute Values

4.6.8 Notifying an Application when State Updates Arrive, describes a protocol-independent way of being notified when an attribute update arrives for a particular object. This was accomplished by registering a postUpdate() callback with a DtReflectedObject.

This section describes an alternate mechanism that works at the level of DtHlaObjects. This method is useful when there are some types of objects that are not managed by a DtReflectedObjectList, or when you want to be notified when an object is updated, regardless of what type of object it is.

In HLA, VR-Link routes attribute updates directly to the DtHlaObject whose attributes the update describes, which may process it however it desires. (Typically, the DtHlaObject decodes the message into its DtReflectedObject's DtStateRepository.) If you want to be notified when an update message has been processed by a DtHlaObject, you can register a callback function with the DtHlaObject using its addPostReflectCb() member function. Use removePostReflectCb() to unregister the callback.

These callback functions should look like the following, as specified in objectReflectAttributeValuesCbInfo.h:

void postReflectCb(const DtStateMsg& msg, DtHlaObject* obj, void* usr);

Your function is called immediately after the DtHlaObject has finished processing the message. Along with the DtHlaObject (and the usr pointer, of course), the message itself is passed to your function.

DtStateMsg (defined in stateMsgHLA.h) is basically a wrapper that contains the ID of an object whose state the message is updating, and the message itself. The information is presented as an RTI::AttributeHandleValuePairSet, the form in which it arrives from the RTI. These two components of a DtStateMsg are available through its objectId() and ahvps() functions respectively.

An example of intercepting reflected attribute values is the netdumpHLA application, which works as follows:

  1. It registers a discoverObject() callback with the DtExerciseConn for all objects of all classes.
  2. Within the discoverObject() callback, netdumpHLA registers a postReflect() callback with each DtHlaObject that is discovered.
  3. Within the postReflect() callback, it prints the contents of the message.

netdumpHLA has versions for HLA 1.3, HLA 1516, and HLA Evolved. For details, please see the appropriate CXX file in ./examples/netdump.

5.5.3 Forcing Attribute Updates

When you call DtObjectPublisher::tick(), it calls down to its DtHlaObject's update() function, which decides which attributes need to be sent, and then sends them. The decision is based on the following factors:

If you want certain eligible attributes to be sent during the next call to a DtObjectPublisher's tick() function, even if their update conditions have not been met, and they have not been specifically requested by a remote federate, you must pass the desired set of attributes to the appropriate DtObjectPublisher's forceUpdate() member function. If you omit the attribute set argument to forceUpdate(), then an update for all eligible attributes is sent during the next call to tick().

5.5.4 Reflecting Locally-Generated Updates

In HLA, you generally do not get discovers from the RTI for objects you register locally, and you do not get reflects from the RTI for updates or interactions that you send locally. For this reason, objects that you simulate locally with DtObjectPublishers will normally not show up in your DtReflectedObjectLists.

VR-Link lets you turn on reflection of locally generated data by calling the DtExerciseConn::setReflecting() function. When "reflecting" is on, objects that you are publishing and updating appear in your reflected object lists. The publisher and reflected object do not share an instance of a state repository. Rather, the reflected object's view of the object is the same as a remote federate's view of the object. The reflected object decodes attribute updates that are generated by a local publisher, just as it decodes updates received from remote federates. Locally-generated interactions are also processed by VR-Link when reflecting is on, so that your interaction callbacks are invoked as they would be for interactions sent by remote federates. The current state of the reflecting flag is obtained using DtExerciseConn::reflecting(). However, once you turn reflecting on in a particular application, you cannot turn it off again.

If you are using ownership management, you should turn on the reflection option, because you may own some attributes of an object, while a remote federate owns other attributes of the same object. With reflecting on, the DtReflectedObject's state repository includes values for all of the attributes, regardless of whether they were sent locally or remotely. (For more information, please see 5.6 - Ownership Management.)

Assuming you have the reflecting option turned on, you can control whether or not you want remotely-generated attribute updates to be decoded into your publisher's state repository in addition to your reflected object's state repository. If this option is off (the default), only local application code can modify the publisher's state repository. If the option is on, then the state repository will contain values decoded from incoming attribute updates for attributes owned by remote federates, plus values you have set for attributes that you own.

Note
The publisher's state repository does not prohibit you from setting values for attributes you do not actually own. Because you do not own the attributes, your data is never sent, and it is overwritten by incoming data when an attribute update arrives from the federate that owns the attribute.

[<< Publishing and Subscribing to FOM Classes and Attributes] [Home] [Top of Page] [Ownership Management >>]


Document ID: Generated on Wed Mar 27 02:04:30 EDT 2024 from SVN revision 264570
Copyright © 2005-2024 MAK Technologies. All Rights Reserved (www.mak.com)