VR-Vantage 2.4 API Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
The Distributed Simulation Tutorial - Add a Detonation Interaction Callback

Introduction to Project 3A

Project 3A in the Distributed Simulation tutorial takes a look at how to add a detonation interaction callback to the simulation connection using VR-Link, and needs to be tested against a running version of VR-Forces in order to see interactions as they come through. For this project, and all projects going forward, we will use a non-threaded connection for simulation data access.

Examining the files that make up the project

For this project, all files from Project 2A will be reused. No new files will be needed. All changes, other than filenames, will be made in the DistributedSimulationDriver class files.

Adding a Detonation Interaction Callback

To add a detonation callback, we will need to add a static callback function and the non-static object-level function that will actually respond to the callback. These will be added to the DistributedSimulationDriver class. We add the callback function, associated with our simulation connection object. The callback function will make a call to the object-level function, passing it the incoming detonation interaction data.

The first thing we need to do is to add the declarations for both a processDetonationCb() and a processDetonation() function to the driver header file. Both of these need to be able to take a pointer to a DtDetonationPdu object. Although not necessary, for better readability, we can define a more self-documenting type name:

typedef DtDetonationPdu DtDetonationInteraction;

//! Static callback function takes detonation interaction and user object as parameters.
static void processDetonationCb(DtDetonationInteraction* inter, void* usr);
virtual void processDetonation(DtDetonationInteraction* inter) const;

In order to instantiate and use a DtDetonationPdu, which we have renamed to DtDetonationInteraction, we have to include the detonateInter.h header.

The new onStart() function looks as follows:

bool DistributedSimulationDriver::onStart()
{
std::cout << "DistributedSimulationDriver::onStart(): " << std::endl;
init.setPort(3152);
init.setExerciseId(1);
init.setSiteId(2);
init.setApplicationNumber(1);
// VR-Link default buffer is to small for this application; set it to 1 MB.
init.setReceiveBufferSize(0x100000);
DtExerciseConn::InitializationStatus status = DtExerciseConn::DtINIT_SUCCESS;
try
{
myConnection = new DtExerciseConn(init, &status);
}
catch(...)
{
return false;
}
myConnectionState = (status == DtExerciseConn::DtINIT_SUCCESS);
// Add a detonation interaction callback
DtDetonationInteraction::addCallback(myConnection, &processDetonationCb, this);
return myConnectionState;
}

The difference between this version and the version in Project 2A is that we have added an addCallback call, passing the connection that we have just instantiated and a reference to our callback function, with the third parameter being the pointer to the object (this) that owns the callback function.

// Add a detonation interaction callback
DtDetonationInteraction::addCallback(myConnection, &processDetonationCb, this);

Now, when the connection receives detonation interaction data, the newly added processDetonationCb() static callback will be invoked, and it will be passed a DtDetonationInteraction pointer, and the pointer to the actual instance object that owns the locally defined function which the callback will call. In the callback, this actual instance object is cast to the correct type of DistributedSimulationDriver, at which point the local processing function can be called.

void DistributedSimulationDriver::processDetonationCb(DtDetonationInteraction* inter, void* usr)
{
((DistributedSimulationDriver*)usr)->processDetonation(inter);
}

The locally defined processing function then looks as follows, printing out that a detonation interaction has been received, and then printing some arbitrarily chosen interaction data values:

void DistributedSimulationDriver::processDetonation(DtDetonationInteraction* inter) const
{
std::cout << "((detonation interaction))";
std::cout << "D(" << inter->attackerId().entityNum() << "," << inter->targetId().entityNum() << "," << inter->result() << ")";
}

The files changed to add this functionality are as follows:

Testing the plugin

Invoke either the tutorialDistributedSimulation3Ad.bat or tutorialDistributedSimulation3A.sh script file to start the VR-Vantage Stealth application. Follow these instructions to test the plugin:

  1. Choose File > View > Drivers Panel.
  2. Select the driver named "DistributedSimulationDriver3A".
  3. Click on the Start button.
  4. You will see in the console window that the text "DistributedSimulationDriver::onStart():" has printed, and on the subsequent line, a series of dots is now continually being printed. Each dot is followed by the number of PDUs read in from the simulation connection.
  5. Start up a VR-Forces application using DIS as the protocol, open a scenario that has at least one detonation in it (the Makland scenario has many), and then start the scenario. As before, the number of PDUs will increase notably, but once there is a detonation shown in VR-Forces, you will see the text "((detonation interaction))" printed in the console window, followed by D(x,y,z), where x, y, and z are arbitrarily chosen values from the detonation interaction object.
  6. Go back to Stealth, make sure the same driver is selected in the Drivers Panel, and click the Stop button.
  7. You will see in the console window that the dots, byte counts, and detonations are no longer being printed, and that the text "DistributedSimulationDriver::onStop():" has been printed on the subsequent line. Note that if detonations occur in VR-Forces during the time that the driver is stopped, these interactions will never be received by the driver, even after it is restarted.
  8. Continually clicking the Start and Stop button will keep starting and stopping the driver, giving these same results in the console window.

[<< Create a Threaded Connection] [Add a Detonation Listener >>]


Project Files

DistributedSimulationDriver3A.h

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
class DtExerciseConn;
class DtDetonationPdu;
typedef DtDetonationPdu DtDetonationInteraction;
namespace makVrv
{
namespace tutorialDistributedSimulation3A
{
class DistributedSimulationDriver : public DtDriver
{
public:
virtual const std::string& className() const;
protected:
virtual bool onStart();
virtual bool onStop();
virtual bool onTick();
static void processDetonationCb(DtDetonationInteraction* inter, void* usr);
virtual void processDetonation(DtDetonationInteraction* inter) const;
protected:
DtExerciseConn* myConnection;
};
}
}

DistributedSimulationDriver3A.cxx

/******************************************************************************
** Copyright (c) 2014 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#define DtDIS 1
#include <vrvCore/DtDe.h>
#include <vl/exerciseConnInitializer.h>
#include <vl/exerciseConn.h>
#include <vl/detonationInteraction.h>
#include <iostream>
namespace makVrv
{
namespace tutorialDistributedSimulation3A
{
DtAgentManager& agentManager, const std::string& instanceName)
: DtDriver(agentManager, instanceName)
, myConnection(0)
, myConnectionState(0)
{
}
DistributedSimulationDriver::~DistributedSimulationDriver(void)
{
}
const std::string& DistributedSimulationDriver::className() const
{
// name must be static, since it's returned by reference
static std::string name("DistributedSimulationDriver");
return name;
}
bool DistributedSimulationDriver::onStart()
{
std::cout << "DistributedSimulationDriver::onStart(): " << std::endl;
init.setPort(3152);
init.setExerciseId(1);
init.setSiteId(2);
init.setApplicationNumber(1);
// VR-Link default buffer is to small for this application; set it to 1 MB.
init.setReceiveBufferSize(0x100000);
DtExerciseConn::InitializationStatus status = DtExerciseConn::DtINIT_SUCCESS;
try
{
myConnection = new DtExerciseConn(init, &status);
}
catch(...)
{
return false;
}
myConnectionState = (status == DtExerciseConn::DtINIT_SUCCESS);
// Add a detonation interaction callback
DtDetonationInteraction::addCallback(myConnection, &processDetonationCb, this);
return myConnectionState;
}
bool DistributedSimulationDriver::onStop()
{
// NOTE: breakdown code goes here. Return false on bad status.
std::cout << "DistributedSimulationDriver::onStop(): " << std::endl;
delete myConnection;
myConnection = 0;
return true;
}
bool DistributedSimulationDriver::onTick()
{
// printout to show whether or not connected at the tick level
if (myConnectionState)
{
int numread = myConnection->drainInput();
std::cout << "." << numread;
}
else
std::cout << "x";
return myConnectionState;
}
void DistributedSimulationDriver::processDetonationCb(DtDetonationInteraction* inter, void* usr)
{
((DistributedSimulationDriver*)usr)->processDetonation(inter);
}
void DistributedSimulationDriver::processDetonation(DtDetonationInteraction* inter) const
{
std::cout << "((detonation interaction))";
std::cout << "D(" << inter->attackerId().entityNum() << "," << inter->targetId().entityNum() << "," << inter->result() << ")";
}
}
}

DistributedSimulationPlugin3A.h

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
// Setup proper plugin export symbol
#ifdef WIN32
#define DT_DE_PLUGIN_EXPORT_MACRO __declspec ( dllexport )
#else
#define DT_DE_PLUGIN_EXPORT_MACRO
#endif
// Declare & export the plugin initialization function (bool initDeModule(DtDe* de))
namespace makVrv { class DtDe; }
// Work function for the plugin initialization
void init(makVrv::DtDe& de);
// Callback to create the stateViewDriver

DistributedSimulationPlugin3A.cxx

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <vrvCore/DtDe.h>
#include <boost/bind.hpp>
using namespace makVrv;
using namespace tutorialDistributedSimulation3A;
{
// We're done with the signal, so disconnect from it
// Create the driver that will implement a distributed simulation
DistributedSimulationDriver* driver = new DistributedSimulationDriver(
de->agentManager(), "DistributedSimulationDriver3A");
// After the driver is added to the display engine below, the DE will manage
// its memory. This driver will add itself to the connection list. Start
// it from the connection panel.
de->driverManager().addDriver(driver);
}
void init(DtDe& de)
{
// Ensure that init only gets called once
// (not strictly necessary here, but this is good practice in general)
// We only want to create the driver if we're running in master mode:
if (de.isInMasterMode())
{
// The driver must be created after the DE's initialization is
// finished, to make sure all the objects it uses exist.
}
}
{
// Setup the plugin. Normally, the init function and functionality
// should be in its own library.
init(*de);
return true;
}


Copyright © 2005-2018 VT MAK. All Rights Reserved (www.mak.com)