The f18 program simulates a simple HLA or DIS vehicle.
By default, that vehicle is an F/A-18 flying in a circle, just off the coast of California, USA, but you can control the entity type, location and route.
The f18 generates predictable HLA entity update messages (or DIS entity state PDUs), so it is a useful tool for debugging applications that receive and interpret these messages. It can also fire munitions, react to detonations, enable/disable IFF Systems, and send lethal interactions.
Major Components of the F18 Example
The F18 is composed of two major classes:
The Vehicle Sim Class
The class DtVehicleSim is responsible for simulating the Aircraft. This includes implementation of the emitter and IFF systems and the detonation and IFF interactions.
The F18 Initialization Class
The DtF18Initializer class is a subclass of VR-Link's DtVrlApplicationInitializer. This class processes the command line and reads the F18's mtl file.
VR-Link Advanced Configuration
The F18 Config Example Code config.cxx serves an an example of how to re-configure VR-Link to interpret FOM attributes and parameters differently. Specifically, after calling the configVrl function on a DtExerciseConn, a VR-Link-based application will assume that the "Position" atttribute of the "BaseEntity" object class (and its subclasses) should be encoded in outgoing messages and interpreted in incoming messages as three doubles in the order: Z, Y, X, rather than the standard X, Y, Z. The same will be true for the "FiringLocation" parameter of the "WeaponFire" interaction.
To demonstrate modifying the FOM to replace existing attributes or parameters, you can edit the .fed file to replace "Position" and "FiringLocation" with different attribute and parameter names, such as "ReversePosition" and "ReverseFiringLocation". If you do this, you will need to replace the names in this file as well (in the calls to addAttributeEncoder, addAttributeDecoder, addParameterEncoder and addParameterDecoder), so that the encoding and decoding functions will be associated with the correct parameter and attribute names.
This file is commented out and not part of the default f18. To add this functionality, compile with DtReverse defined.
How to Run the Example
- Launch 2 F18 examples from your VR-Link install's bin64 directory using the same protocol.
- To toggle enabling and disabling of Emitters, press the 'e' key in the F18 console application.
- To change emitter beam scan data for this aircraft, press the 'd' key.
- To toggle enabling and disabling of IFF, press the 'i' key.
- To toggle enabling and disabling of Lethal IFF Interrogation, press 'l' key.
- To send an interrogation of Mode 5, press the '5' key.
- To send a Lethal IFF Interaction, press the 's' key.
- To fire munitions at a nearby target, press the 'f' key.
- For usage information, press the 'h' key.
- To exit, press the 'q' key.
- Note
- To send any interrogation, the IFF System for the aircrafts must be enabled. Lethal Interrogation will only force a Mode 5 Reply, regardless of Mode 5 IsOn attribute status. Interrogations will only provide transponder information for Modes included in the interrogation whose isOn attribute is set to true.
Example Code
Main Application
#include <stdlib.h>
#include <iostream>
#ifndef _WIN32
#include <sys/socket.h>
#endif
DtTime timeOutInterval = 12.0;
double translationThreshold = 1.0;
static int keybrdTick( );
#if VXWORKS
#define main realMain
#endif
int main( int argc, char* argv[] )
{
try
{
DtString appName =
"VR-Link F18 " + pidStr;
#if DtDIS
initializer.setDisVersionToSend( 7 );
#else
initializer.setFedFileName( DtDefaultRpr2Fom );
initializer.setExecName( "MAK-One-2024" );
initializer.setRprFomVersion( 2.0 );
initializer.setRprFomRevision( 1 );
#ifdef DtHLA_1516_EVOLVED
initializer.addFomModule("NETN-BASE.xml");
initializer.addFomModule("NETN-Physical.xml");
initializer.addFomModule("NETN-METOC.xml");
initializer.addFomModule("NETN-MRM.xml");
initializer.addFomModule("MAK-Physical-2_evolved.xml");
initializer.addFomModule("MAK-Aerodrome-1_evolved.xml");
initializer.addFomModule("MAK-METOC-1_evolved.xml");
initializer.addFomModule("MAK-VRFExt-9_evolved.xml");
initializer.addFomModule("MAK-DIGuy-7_evolved.xml");
initializer.addFomModule("MAK-LgrControl-2_evolved.xml");
initializer.addFomModule("MAK-VRFAggregate-6_evolved.xml");
initializer.addFomModule("MAK-DynamicTerrain-2_evolved.xml");
initializer.addFomModule("MAK-VRLExt-3_evolved.xml");
initializer.addFomModule("RPR-Enumerations_Experimental_IFF.xml");
initializer.addFomModule("RPR-MAK_Experimental_IFF-3.xml");
#endif
#endif
initializer.parseCmdLine();
initializer.setApplicationNumber( pid );
DtString defaultF18Name( initializer.f18Name() );
defaultF18Name += " " + pidStr;
initializer.setF18Name( defaultF18Name );
#ifdef DtHLA
initializer.setFederateType( "Parallel F18" );
initializer.setFederateName(defaultF18Name);
#endif
#if DtDIS
initializer.setUseAsynchIO(true);
#endif
#ifdef DtHLA
std::cout <<
"[" << clock->
elapsedRealTime() <<
", 0] Initializing" << std::endl;
exConn->setExecutionStatus(vrlstatus_initializing);
#endif
DtTime frameTime = initializer.deltaTime();
#ifdef DtHLA
exConn->setExecutionStatus(vrlstatus_initialized);
std::cout <<
"[" << clock->
elapsedRealTime() <<
", 0] Initialized" << std::endl;
#endif
int forever = 1;
double outputInterval = initializer.outputInterval();
#ifdef DtHLA
std::cout <<
"[" << clock->
elapsedRealTime() <<
", 0] Executing" << std::endl;
exConn->setExecutionStatus(vrlstatus_executing);
#endif
unsigned long frameCount = 1;
double totalDrainDuration = 0.0;
double totalSimDuration = 0.0;
double totalPubDuration = 0.0;
double totalIdle = 0.0;
double totalFrameDuration = 0.0;
int numberFrameOverflows = 0;
double totalOverflow = 0.0;
std::cout << std::fixed;
while( forever )
{
dt = startTime - lastTime;
totalDrainDuration += drainDuration;
totalSimDuration += simDuration;
totalPubDuration += pubDuration;
totalFrameDuration += frameDuration;
if (frameDuration < frameTime)
{
idle = frameTime - frameDuration;
totalIdle += idle;
dt = frameTime;
}
else
{
dt = frameDuration;
idle = -1.0;
numberFrameOverflows++;
totalOverflow += frameDuration - frameTime;
}
if (outputInterval <= 0.0 || outputTime < startTime)
{
std::cout <<
"[" << std::setprecision(2) << simulator.
simTime() <<
", " << frameCount <<
"] #entities: " << simulator.
numberRemoteEntities()
<< " total=" << std::setprecision(6) << frameDuration << "(" << totalFrameDuration / frameCount << ")"
<< " idle=" << idle << "(" << totalIdle/frameCount << ")"
<< " drain=" << drainDuration << "(" << totalDrainDuration / frameCount << ")"
<< " sim=" << simDuration << "(" << totalSimDuration / frameCount << ")"
<< " pub=" << pubDuration << "(" << totalPubDuration / frameCount << ")"
<< " #FO=" << numberFrameOverflows << "(" << (numberFrameOverflows > 0 ? totalOverflow/numberFrameOverflows : 0) << ")"
<< std::endl;
numberFrameOverflows = 0;
totalOverflow = 0.0;
}
if (idle > 0.0)
{
}
lastTime = startTime;
frameCount++;
}
}
return 0;
}
Vehicle Sim Class
Vehicle Sim Header
#pragma once
{
public:
const char* name, const char* markings,
double initHeading, double initTRadius,
double initPitch, bool autoRoll, double initRoll, int num );
public:
protected:
protected:
protected:
protected:
};
Vehicle Sim Source
#include "vehicleSim.h"
#ifndef effZero
#define effZero 1.0E-30
#endif
const char* name, const char* markings,
myTimeSpacing(timeSpacing),
myPublishedObjects(pubContainer),
mySysPub( 0 )
{
#if DtHLA
#elif DtDIS
#else
#error "Please Choose Protocol!"
#endif
myPublishedObjects.add(myEntityPub);
myESR = myEntityPub->entityStateRep();
myESR->setEntityType( type );
myESR->setGuise( type );
myESR->setMarkingText( markings );
myESR->setAlgorithm( alg );
myESR->setEntityId( id );
myTopoView =
new DtTopoView( myESR, refLat, refLon );
myRel = rel;
myFire = 0;
myDetonateTime = 0.0;
myTimeDestroyed = -1.0;
myIsDestroyed = false;
myEmissionsEnabled = false;
myHaveArtParts = haveArtParts;
}
{
}
double initHeading, double initTRad,
double initPitch, bool autoRoll, double initRoll, int num)
{
myTurnRate = ( ( initTRad != 0.0 ) ? ( initSpeed / initTRad ) : 0.0 );
double roll = ( autoRoll ) ?
float cosPsi = cos( psi );
float sinPsi = sin( psi );
float cosPhi = cos( phi );
float sinPhi = sin( phi );
for (int i = 0; i < 3; i++)
{
}
{
}
}
{
for( int i=0; i<3; ++i )
{
}
{
}
}
{
{
}
else
{
}
{
}
else
{
}
}
{
}
{
{
}
}
{
double distance;
{
{
{
DtInfo <<
"Direct hit! Going down!" << std::endl;
return 1;
}
}
{
{
DtInfo <<
"Indirect hit only " << distance <<
" m away! Going down!"
<< std::endl;
return 1;
}
else
{
return 0;
}
}
default:
{
return 0;
}
}
}
{
myTurnRate= 0.0;
}
{
{
DtInfo <<
"Emissions enabled." << std::endl;
#if DtHLA
#endif
}
}
{
{
DtInfo <<
"Emissions disabled." << std::endl;
}
}
{
{
}
else
{
}
}
{
{
}
}
{
double minDistSqr = 0.0;
entity;
entity = entity->
next() )
{
if ( entity->id() == me ) continue;
entity->entityStateRep()->location(), geocPos );
if ( distSqr < minDistSqr || !nearest )
{
nearest = entity;
minDistSqr = distSqr;
}
}
return nearest;
}
{
if ( nearest )
{
}
}
{
{
return;
}
#if DtHLA
#endif
DtInfo <<
"Sending fire interaction" << std::endl;
}
{
{
return;
}
det.setMunitionType(sidewinder);
det.setEntityLocation(
DtVector32( 0.0, 0.0, 0.0 ) );
if ( ent )
{
det.setVelocity(velocity);
}
else
{
}
DtInfo <<
"Sending detonation interaction" << std::endl;
}
{
{
}
}
{
}
{
}
{
}
{
}
F18 Initializer Class
F18 Initializer Header
#pragma once
{
public:
private:
public:
#ifdef DtHLA_1516_EVOLVED
virtual void setSuppressDefaultModules(bool onOff);
virtual bool suppressDefaultModules();
#endif
#if DtHLA
#endif
protected:
protected:
#ifdef DtHLA_1516_EVOLVED
#endif
#if DtHLA
#endif
};
F18 Initializer Source
#include <stdio.h>
, myInitialPosition( mySettings,
"initialPosition",
DtVector(0.0,0.0,-1230.0),
, myLispFileName( mySettings, "&lispFile", "f18.xml", "LISP File Name" )
, myDeadReckonAlgorithm( mySettings,
"deadReckonAlgorithm",
DtDrDrmRvw,
"Dead Reckon Algorithm",
, myInitialTurnRadius( mySettings, "initialTRadius", -250.0, "Initial Turn Radius",
, myInitialSpeed( mySettings, "initialSpeed", 40.0, "Initial Speed" )
, myEntityTypeString( mySettings, "entity&TypeStr", "1:2:225:1:9:0:0", "Entity Type String" )
, myMarkings( mySettings, "f18&Markings", "MAK-VRLink-F18", "F18 Markings" )
, myName( mySettings, "f18Name", "MAK-F18", "F18 Object Name" )
, myDestroyedToFinalDelay( mySettings, "&destroyedToFinalDelay", 20.0,
"Destroyed To Final Delay" )
, myInitialHeading( mySettings, "initial&Heading", 180.0, "Initial Heading" )
, myTopoOrigin( mySettings, "topo&Origin", "35.699760,-121.326577",
"Topographic Coordinate System Origin" )
, myWorldPosition( mySettings,
"worldPos",
DtVector(0.0,0.0,0.0),
, myLethalDetonationRange( mySettings, "lethalDetonationRange", 20.0, "Lethal Detonation Range",
, myMunitionFlightTime( mySettings, "munitionFlightTime", 3.0, "Munition Flight Time",
, myInitialPitch( mySettings, "initialPitch", 0.0, "Initial Pitch",
, myInitialRoll( mySettings, "initialRoll", 0.0, "Initial Roll",
, myAutoRoll( mySettings, "autoRoll", true, "Auto Roll",
, myEntityNumber( mySettings, "entNum", 1, "Entity Number",
, myHaveArtParts( mySettings, "haveArtParts", false, "Have Articulated Parts",
, myRefLatitude( mySettings, "refLatitude", 35.699760, "Reference Latitude",
, myRefLongitude( mySettings, "refLongitude", -121.326577, "Reference Longitude",
, myDeltaTime( mySettings, "deltaTime", 0.05, "Delta Time",
#ifdef DtHLA_1516_EVOLVED
, mySuppressDefaultModules( mySettings, "suppressDefaultModules", false, "Suppress Default Modules (HLA1516-2010 only)",
#endif
, myMtlAutoRoll( 1 )
#if DtHLA
, myConfigVarApplicationNumber(mySettings, "&appNumber", 2, "Application Number")
, mySiteId(mySettings, "&siteId", 1, "Site ID")
#endif
, myMtlHaveArtParts( 0 )
, myMtlInitialPosition( 0.0, 0.0, -1230.0 )
{
mySettings.setChangeOnce(true);
}
{
}
{
#if DtHLA
#endif
}
{
for (
int index = 1; index <
myArgc; ++index )
{
if ( ! strcmp(
myArgv[index],
"-l") || ! strcmp(
myArgv[index],
"--lispFile") )
{
if ( index + 1 < myArgc )
{
break;
}
}
}
{
posVec[2] = -posVec[2];
}
{
if ( numReads > 0 )
{
if ( numReads > 1 )
{
}
}
}
{
}
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
#ifdef DtHLA_1516_EVOLVED
void DtF18Initializer::setSuppressDefaultModules(bool onOff)
{
mySuppressDefaultModules.setValue(onOff);
}
bool DtF18Initializer::suppressDefaultModules()
{
return mySuppressDefaultModules.value();
}
#endif
{
}
#if DtHLA
{
}
{
}
{
}
{
}
#endif
F18 Config Example Code
#if DtHLA
#if DtReverse
RTI::AttributeHandleValuePairSet* avList,
RTI::AttributeHandle handle )
{
}
const RTI::AttributeHandleValuePairSet& avlist,
int pairSetIndex )
{
RTI::ULong length = 0;
avlist.getValue( pairSetIndex, (char*)&netVal, length );
}
RTI::ParameterHandleValuePairSet* pvList,
RTI::ParameterHandle handle )
{
}
const RTI::ParameterHandleValuePairSet& pvlist,
int pairSetIndex )
{
RTI::ULong length = 0;
pvlist.getValue( pairSetIndex, (char*)&netVal, length );
}
{
exConn->fomMapper()->stateEncoderFactory()->
addAttributeEncoder( "BaseEntity", "Position",
(DtHlaStateEncoder::DtAttributeEncoder)DtPosEncoder );
exConn->fomMapper()->stateDecoderFactory()->
addAttributeDecoder( "BaseEntity", "Position",
(DtHlaStateDecoder::DtAttributeDecoder)DtPosDecoder );
exConn->fomMapper()->interactionEncoderFactory()->
addParameterEncoder( "WeaponFire", "FiringLocation",
(DtInteractionEncoder::DtParameterEncoder)DtFirePosEncoder );
exConn->fomMapper()->interactionDecoderFactory()->
addParameterDecoder( "WeaponFire", "FiringLocation",
(DtInteractionDecoder::DtParameterDecoder)DtFirePosDecoder );
}
#endif // DtReverse
#endif // DtHLA