VR-Link API Documentation for HLA 1516
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Example FOM Mapper

Table of Contents

The FOM Mapper Example

This Example FOM Mapper shows how to create a FOM Mapper for a new FOM, but assumes that the new FOM contains concepts already covered by VR-Link's API, so no extensions are necessary.

It also demonstrates how to put the new FOM Mapper into a shared library that can be loaded by DtExerciseConn, and by MAK applications like MAK Stealth, MAK Data Logger, and VR-Forces. The shared library works with the FED file called example-MyFomMap.fed that is in the VR-Link root directory.

Implementation

For this example, we created a new FED file called example-MyFomMap.fed, representing a new, simple FOM. The MyFomMap FOM contains one object class called Vehicle, and one interaction class called Shoot.

The Vehicle Object Class

Vehicle has two attributes:

These attributes are mapped to DtEntityStateRepository's concepts of entity type and location.

The Shoot Interaction Class

Shoot has two parameters:

Both parameters are character strings representing the HLA object names of the attacker and target respectively. These parameters will be mapped to DtFireInteraction's concepts of attacker ID and target ID respectively.

The New MyFomMap FOM

This FOM uses different class, attribute, and parameter names than the RPR FOM, but uses similar data representations to keep our type conversion examples simple. (Though in one case - the VehicleType attribute, our data representation is very different to demonstrate that this can be done.)

For each of these FOM classes, the example:

  1. Creates an encoder class and a decoder class whose constructors self-register the necessary encoding and decoding functions for each attribute and parameter (and checking functions for each attribute as well.)
  2. Registers these encoders and decoders with a FOM Mapper along with other class mapping information.
  3. Implements the two global functions required for FOM Mapper shared libraries.

Using the FOM Mapper

When you execute make in the example directory, you build a shared library called myFomMap<protocol>.so or myFomMap<protocol>.dll. You can test this library with any VR-Link example that accepts a path to a FOM mapping shared library (through the -f option.) You can omit the .so or .dll, so that the same command can be used in Windows or in UNIX. Remember to also specify a federation execution name of MyFomMap, using the -x option, so that the example-MyFomMap.fed file is used.

For example, from the ./bin64 directory, you can run the following commands for the protocol of choice:

Alternatively, you can write your own application that passes the name of the shared library to the DtExerciseConn. Again, make sure that you use the right FED or FOM file:

DtExerciseConn conn("MyFomMap", "MyApp", "myFomMap");

MyFomMap Plugin

The myFomMap.cxx file contains the main class MyFomMapper which is created by the plugin manager.

There are several ways to configure a FOM Mapper to work with this new FOM. For example, you could allow the DtExerciseConn constructor to create an empty FOM Mapper, and then add mappings to that FOM Mapper later.

However, this example creates a subclass of DtFomMapper called MyFomMapper, whose implementation of the virtual init() function self registers all of the mappings we want. Then it can either create an instance of this class and pass it to the DtExerciseConn constructor, or create a shared library containing a function called DtCreateFomMapper() that returns a new'ed instance of MyFomMapper, and pass the name of the shared library to the DtExerciseConn constructor. This example uses the shared library option.

Regardless of how an instance of a DtFomMapper is passed to a DtExerciseConn constructor, DtExerciseConn calls init() on that FOM Mapper after reading the FED file and initializing the RTI.

The MyFomMapper class is defined in myFomMap.h and myFomMap.cxx. The code is included below. Notice that MyFomMapper is derived from DtEmptyFomMapper. Within MyFomMapper::init(), call down to the DtEmptyFomMapper::init(), which initializes the FOM Mapper with empty factories and tables. Then add your own mappings to the tables, including adding instances of our encoders and decoders to the FOM Mapper's encoder and decoder factories.

Creating DLL Hooks for your FOM Mapper

The createFomMap.cxx source file is the entry point for the DLL. It contains definitions for the functions that are required by VR-Link if you are creating a FOM Mapper shared library. When you pass the name of a shared library to a DtExerciseConn constructor, it opens the shared library and looks for the functions DtCreateFomMapper() and DtDeleteFomMapper(). Here, DtCreateFomMapper() just returns a new instance of our MyFomMapper class. These two functions must have C linkage, so we enclose their definitions within extern "C" {}.

Encoding and Decoding Objects and Interactions

The VehicleEncoder and VehicleDecoder show how to encode and decode the attributes of an object.

The ShootEncoder and ShootDecoder show how to encode and decode the parameters of an interaction.

Example FOM Mapper Code

Main Application

Header

/*********************************************************************
** Copyright (c) 1998 MaK Technologies, Inc.
** All rights reserved.
*********************************************************************/
#pragma once
#include <vlutil/vlConfig.h>
// Export Symbols on Windows (and do nothing on Linux)
#if DT_NEED_DLL_DECLARATIONS
#ifdef DT_DLL_FOMMAP
#undef DT_DLL_FOMMAP
#define DT_DLL_FOMMAP __declspec( dllexport )
#else
#define DT_DLL_FOMMAP __declspec( dllimport )
#endif
#else
#ifdef DT_DLL_FOMMAP
#undef DT_DLL_FOMMAP
#endif
#define DT_DLL_FOMMAP
#endif
#if DtHLA
{
public:
// Default constructor - most initialization is delayed until init() is
// called.
// Destructor
virtual ~MyFomMapper();
// Virtual function override. init actually initializes most data. It is
// called from DtExerciseConn constructor. Required.
virtual void init(DtExerciseConn* conn);
protected:
// Copy Ctor Not implemented
MyFomMapper(const MyFomMapper&orig);
};
#endif

Source Code

/*********************************************************************
** Copyright (c) 1998 MaK Technologies, Inc.
** All rights reserved.
*********************************************************************/
/*********************************************************************
** $RCSfile: myFomMap.cxx,v $ $Revision: 1.2 $ $State: Exp $
*********************************************************************/
#if DtHLA
#include <vl/fom.h>
#include "myFomMap.h"
#include "shootDec.h"
#include "shootEnc.h"
#include "vehicleDec.h"
#include "vehicleEnc.h"
{
// Real initialization takes place in virtual init() function,
// when a DtExerciseConn is available.
}
{
// Call base class init. This sets myExConn, and initializes all factories
// to default or empty factories (no encoders or decoders registered, no
// mappings between FOM interaction classes and VR-Link interaction
// classes.
// Add encoders and decoders for our Vehicle object class and Shoot
// interaction class. When DtEntityPublisher, DtReflectedEntity, and
// DtFireInteraction ask the FOM mapper for encoders and decoders to use,
// this FOM mapper will return clones of the encoders and decoders we're
// registering here.
DtObjClassDesc* objClass = exConn->fom()->objClassByName("Vehicle");
if (objClass)
{
objClass->handle(), new VehicleEncoder(exConn, objClass));
objClass->handle(), new VehicleDecoder(exConn, objClass));
}
DtInterClassDesc* interClass = exConn->fom()->interClassByName("Shoot");
if (interClass)
{
interClass->handle(), new ShootEncoder(exConn, interClass));
interClass->handle(), new ShootDecoder(exConn, interClass));
}
// Set up mappings for publishing. Indicate the FOM class to use for each
// kind of DtObjectPublisher, and each kind of DtInteraction.
setObjectClassToChoose("DtEntityPublisher", "Vehicle");
setInteractionClassToChoose("DtFireInteraction", "Shoot");
// Set up mappings for subscribing. Indicate which FOM class each kind of
// DtReflectedObjectList should subscribe to, and which FOM class each kind
// of DtInteraction's addCallback function should subscribe to.
setObjectClass("DtReflectedEntityList", "Vehicle");
setInteractionClass("DtFireInteraction", "Shoot");
// Set up mappings for creating DtInteraction instances. Indicate what
// kind of DtInteraction to create to represent each FOM interaction
// class.
}
{
}
#endif

Create FOM Map

Source Code

/*********************************************************************
** Copyright (c) 1997 MaK Technologies, Inc.
** All rights reserved.
*********************************************************************/
#include "myFomMap.h"
extern "C"
{
DT_DLL_FOMMAP DtFomMapper* DtCreateFomMapper(void* usr)
{
return new MyFomMapper();
}
DT_DLL_FOMMAP void DtDeleteFomMapper(DtFomMapper* mapper)
{
delete mapper;
}
}

Vehicle Encoder

Header

/*********************************************************************
** Copyright (c) 1998 MaK Technologies, Inc.
** All rights reserved.
*********************************************************************/
#if DtHLA
#ifndef VehicleEncoder_H_
#define VehicleEncoder_H_
#include "myFomMap.h"
#define DtDECLARE_TEST_ATTR_CHECKER(attrName) \
DtDECLARE_ATTR_CHECKER(DtEntityStateRepository, attrName)
#define DtDECLARE_TEST_ATTR_ENCODER(attrName) \
DtDECLARE_ATTR_ENCODER(DtEntityStateRepository, attrName)
{
public:
// default constructor
// destructor
virtual ~VehicleEncoder();
protected:
// Individual attribute encoding functions - one for each attribute.
// This macro expands to look like this:
// static void encodeVehicleType(const DtEntityStateRepository& rep,
// RTI::AttributeHandleValuePairSet* attrs,
// RTI::AttributeHandle attrHandle)
// Individual attribute checking functions - one for each attribute.
// This macro expands to look like this:
// static bool needNumber(const DtEntityStateRepository& rep,
// const DtEntityStateRepository& asSeenByRemote);
};
#endif
#endif

Source Code

/*********************************************************************
** Copyright (c) 1998 MaK Technologies, Inc.
** All rights reserved.
*********************************************************************/
/*********************************************************************
** $RCSfile: vehicleEnc.cxx,v $ $Revision: 1.4 $ $State: Exp $
*********************************************************************/
#if DtHLA
#include "vehicleEnc.h"
DtExerciseConn* exConn,
DtObjClassDesc* classDesc) :
DtHlaStateEncoder(exConn, classDesc)
{
// Register the individual encoding and checking functions for Vehicle's
// attributes with the object. The encoding functions have names like
// encodeGeocLoc, while checking functions have names like needGeocLoc.
// The macros expands to look like this:
// addEncoder("VehicleType", (DtAttributeEncoder) encodeVehicleType);
// addChecker("VehicleType", (DtAttributeChecker) needVehicleType);
DtADD_ATTR_ENCODER(VehicleType);
DtADD_ATTR_CHECKER(VehicleType);
}
{
}
// Encoding and checking functions
// Macros can help with definitions of simple encoding and checking functions,
// as in in examples/extend/testObj/testEnc.cxx but here we do not rely on
// them.
bool VehicleEncoder::needVehicleType(
const DtEntityStateRepository& stateRep,
const DtEntityStateRepository& asSeenByRemote)
{
return (bool) !(stateRep.entityType() == asSeenByRemote.entityType());
}
bool VehicleEncoder::needGeocLoc(
const DtEntityStateRepository& stateRep,
const DtEntityStateRepository& asSeenByRemote)
{
return (bool) !(stateRep.location() == asSeenByRemote.location());
}
void VehicleEncoder::encodeVehicleType(const DtEntityStateRepository& rep,
RTI::AttributeHandle attrHandle)
{
// Get value using inspector
DtEntityType type = rep.entityType();
// Convert to FOM representation:
DtNetInt32 netVal = 0;
if (type == DtEntityType(1, 1, 225, 1, 1, 0, 0))
{
// M1A1
netVal = 0;
}
else if (type == DtEntityType(1, 1, 222, 1, 2, 0, 0))
{
// T72
netVal = 1;
}
// Add to ahvps
attrs->add(attrHandle, (char*) &netVal, sizeof(netVal));
}
void VehicleEncoder::encodeGeocLoc(const DtEntityStateRepository& rep,
RTI::AttributeHandle attrHandle)
{
// Get the value from the inspector function, convert to FOM representation
// (in this case, a trivial conversion), and add it to the phvps.
DtVector vec = rep.location();
DtNet64Vector netVal(vec);
// Add to ahvps
attrs->add(attrHandle, (char*) &netVal, sizeof(netVal));
}
#endif

Vehicle Decoder

Header

/*********************************************************************
** Copyright (c) 1998 MaK Technologies, Inc.
** All rights reserved.
*********************************************************************/
#if DtHLA
#ifndef VehicleDecoder_H_
#define VehicleDecoder_H_
#include "myFomMap.h"
// Forward declaration of DtEntityStateRepository class.
// We define several macros that can be helpful in defining the class, and the
// individual decoding functions.
#define DtDECLARE_VEHICLE_ATTR_DECODER(attrName) \
DtDECLARE_ATTR_DECODER(DtEntityStateRepository, attrName)
{
public:
// default constructor
// destructor
virtual ~VehicleDecoder();
protected:
// Individual attribute decoding functions - one for each attribute.
// These macros expand to look like this:
// static void decodeVehicleType(DtEntityStateRepository* stateRep,
// const RTI::AttributeHandleValuePairSet& attrs, int pairSetIndex)
};
#endif
#endif

Source Code

/*********************************************************************
** Copyright (c) 1998 MAK Technologies, Inc.
** All rights reserved.
*********************************************************************/
/*********************************************************************
** $RCSfile: vehicleDec.cxx,v $ $Revision: 1.4 $ $State: Exp $
*********************************************************************/
#if DtHLA
#include "vehicleDec.h"
// Default constructor
DtExerciseConn* exConn,
DtObjClassDesc* classDesc) :
DtHlaStateDecoder(exConn, classDesc)
{
// Register the individual decoding functions for Vehicle's attributes with
// the object. The decoding functions have names like decodeVehicleType
// and decodeGeocLoc. The macro expands to look like this:
// addDecoder("VehicleType", (DtAttributeDecoder) decodeVehicleType);
DtADD_ATTR_DECODER(VehicleType);
}
{
}
// Decoding functions
// Macros can help with definitions of simple decoding functions, as in in
// examples/extend/testObj/testDec.cxx but here we do not rely on them.
void VehicleDecoder::decodeVehicleType(DtEntityStateRepository* stateRep,
int index)
{
RTI::ULong length = 0;
// Get value from RTI representation into netVal.
DtNetInt32* netVal = (DtNetInt32*) attrs.getValuePointer(index, length);
// Convert from FOM representation to VR-Link representation.
// Byte swapping occurs if necessary, when converting from "Net" types to
// native types.
int nativeVal = (DtInt32) *netVal;
DtEntityType entityType;
if (nativeVal == 0)
{
// It's an M1.
entityType = DtEntityType(1, 1, 225, 1, 1, 0, 0);
}
else if (nativeVal == 1)
{
// It's a T72.
entityType = DtEntityType(1, 1, 222, 1, 2, 0, 0);
}
// pass the value to the mutator function
stateRep->setEntityType(entityType);
}
void VehicleDecoder::decodeGeocLoc(DtEntityStateRepository* stateRep,
int index)
{
RTI::ULong length = 0;
// Get value from RTI representation into netVal.
DtNet64Vector* netVal =
(DtNet64Vector*) attrs.getValuePointer(index, length);
// In this case, the FOM representation (DtNet64Vector) can be implicitly
// converted to VR-Link representation (DtVector)
stateRep->setLocation(*netVal);
}
#endif

Shoot Encoder

Header

/*********************************************************************
** Copyright (c) 1999 MaK Technologies, Inc.
** All rights reserved.
*********************************************************************/
#ifndef ShootEncoder_H_
#define ShootEncoder_H_
#if DtHLA
#include "myFomMap.h"
#define DtDECLARE_SHOOT_PARAM_ENCODER(paramName) \
DtDECLARE_PARAM_ENCODER(DtFireInteraction, paramName)
{
public:
virtual ~ShootEncoder();
protected:
};
#endif
#endif

Source Code

/*********************************************************************
** Copyright (c) 1997 MAK Technologies, Inc.
** All rights reserved.
*********************************************************************/
/*********************************************************************
** $RCSfile: shootEnc.cxx,v $ $Revision: 1.3 $ $State: Exp $
*********************************************************************/
#if DtHLA
#include "shootEnc.h"
// Constructor.
DtExerciseConn* exConn,
DtInterClassDesc* classDesc) :
DtInteractionEncoder(exConn, classDesc)
{
// Register the individual encoding functions for Shoot's parameters with
// object. The encoding functions have names like encodeShooter and
// encodeShootee. The macro expands to look like this:
// addEncoder("Shooter", (DtParameterEncoder) encodeShooter);
// addEncoder("Shootee", (DtParameterEncoder) encodeShootee);
}
{
}
// Decoding functions
// Macros can help with definitions of simple encoding functions, as in in
// examples/extend/testObj/testEnc.cxx but here we do not rely on them.
void ShootEncoder::encodeShooter(const DtFireInteraction& inter,
RTI::ParameterHandle paramHandle)
{
// Get the value from the inspector function, convert to FOM representation
// (in this case, a trivial conversion), and add it to the phvps.
const char* val = inter.attackerId().string();
params->add(paramHandle, val, strlen(val));
}
void ShootEncoder::encodeShootee(const DtFireInteraction& inter,
RTI::ParameterHandle paramHandle)
{
// Get the value from the inspector function, convert to FOM representation
// (in this case, a trivial conversion), and add it to the phvps.
const char* val = inter.targetId().string();
params->add(paramHandle, val, strlen(val));
}
#endif

Shoot Decoder

Header

/*********************************************************************
** Copyright (c) 1999 MaK Technologies, Inc.
** All rights reserved.
*********************************************************************/
#ifndef ShootDecoder_H_
#define ShootDecoder_H_
#if DtHLA
#include "myFomMap.h"
#define DtDECLARE_SHOOT_PARAM_DECODER(paramName) \
DtDECLARE_PARAM_DECODER(DtFireInteraction, paramName)
{
public:
virtual ~ShootDecoder();
protected:
};
#endif
#endif

Source Code

/*********************************************************************
** Copyright (c) 1997 MaK Technologies, Inc.
** All rights reserved.
*********************************************************************/
/*********************************************************************
** $RCSfile: shootDec.cxx,v $ $Revision: 1.3 $ $State: Exp $
*********************************************************************/
#if DtHLA
#include "shootDec.h"
#include <stdio.h>
#include <string.h>
// Constructor.
DtExerciseConn* exConn,
DtInterClassDesc* classDesc) :
DtInteractionDecoder(exConn, classDesc)
{
// Register the individual decoding functions for Shoot's parameters with
// object. The decoding functions have names like decodeShooter and
// decodeShootee. The macro expands to look like this:
// addDecoder("Shooter", (DtParameterDecoder) decodeShooter);
}
{
}
// Decoding functions
// Macros can help with definitions of simple decoding functions, as in in
// examples/extend/testInter/testDec.cxx but here we do not rely on them.
void ShootDecoder::decodeShooter(DtFireInteraction* inter,
int index)
{
RTI::ULong length = 0;
// Get value in RTI representation into netVal.
char* netVal = (char*)
params.getValuePointer(index, length);
// Must copy to a buffer, because string returned by getValuePointer may
// not be NULL terminated.
static char buff[100];
strncpy(buff, netVal, length);
buff[length] = 0;
// In this case, we can implicitly convert from FOM representation (char*)
// to VR-Link representation (DtGlobalObjectDesignator). No explicit
// conversion is necessary. Just pass the value to the mutator function.
inter->setAttackerId(buff);
}
void ShootDecoder::decodeShootee(DtFireInteraction* inter,
int index)
{
RTI::ULong length = 0;
// Get value in RTI representation into netVal.
char* netVal = (char*)
params.getValuePointer(index, length);
// Must copy to a buffer, because string returned by getValuePointer may
// not be NULL terminated.
static char buff[100];
strncpy(buff, netVal, length);
buff[length] = 0;
// In this case, we can implicitly convert from FOM representation (char*)
// to VR-Link representation (DtGlobalObjectDesignator). No explicit
// conversion is necessary. Just pass the value to the mutator function.
inter->setTargetId(buff);
}
#endif

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)