VR-Forces 4.1 Class Documentation
The Distributed Simulation Tutorial - Create a Non-Threaded Connection

Introduction to Project 2A

Project 2A in the Distributed Simulation tutorial takes a look at how to create a non-threaded connection to the distributed simulation using VR-Link. A connection can be made using any of the following protocols: DIS, HLA 1.3, or HLA 1516. For this project, and for project 2B, we are going to look at creating a DIS connection. We will use that protocol for all subsequent projects.

Examining the files that make up the project

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

Creating a non-threaded VR-Link connection

To create a non-threaded VR-Link connection, we will need to add a DtExerciseConn pointer as a member in the DistributedSimulationDriver class. It is also useful to have a member boolean to keep the current state of the connection. Once these are added to the header file, we can instantiate the connection in the OnStart() function, and make use of it in onTick().

First we want to make a decision as to which protocol we mean to use. Since DIS is the simplest choice, we will add the following at the top of the .cxx file.

#define DtDIS 1

Then we will need to include the necessary VR-Link header files. The exConnInit.h header file routes off to declarations of a DIS, HLA 1.3, or HLA 1516 version of the DtExerciseConnInitializer class which is used for initializing a connection. The DtDIS macro that we defined above will cause the following header to route to the correct version of the exerciseConn.h file for the DIS protocol.

#include <vl/exConnInit.h>

The new onStart() function looks as follows:

{
std::cout << "DistributedSimulationDriver::onStart(): " << std::endl;
DtExerciseConnInitializer init;
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);
}
return myConnectionState;
}

Let's look at this new function. First we instantiate and initialize a connection initializer object which will be passed as the first parameter to the connection constructor. Always make sure that you set the default buffer size to be at least 1MB:

DtExerciseConnInitializer init;
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);

The second input parameter for the connection constructor is an enumeration used for returning the connection status after the connection object has been constructed:

DtExerciseConn::InitializationStatus status = DtExerciseConn::DtINIT_SUCCESS;

Since the connection constructor can throw an exception, we wrap the instantiation of the connection object inside a try block.

try
{
myConnection = new DtExerciseConn(init, &status);
}
catch(...)
{
return false;
}
myConnectionState = (status == DtExerciseConn::DtINIT_SUCCESS);

And then we return the connection state as a boolean.

return myConnectionState;
}

The new onTick() function has also been changed to contain one new call wrapped in an if statement. If the connection state is good, then we want to drain whatever simulation input is waiting for us on the connection. The return value for the drainInput() function is the number of PDUs processed. Again the connection state is returned as the result of the onTick() call.

{
// Printout to show whether or not connected at the tick level
if (myConnectionState)
{
int numread = myConnection->drainInput();
std::cout << "." << numread;
}
else
{
std::cout << "x";
}

The new onStop() function looks as follows:

{
// NOTE: breakdown code goes here. Return false on bad status.
std::cout << "DistributedSimulationDriver::onStop(): " << std::endl;
delete myConnection;
myConnection = 0;
return true;
}

The files changed to add this functionality are as follows:

Testing the plugin

Invoke either the tutorialDistributedSimulation2Ad.bat or tutorialDistributedSimulation2A.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 "DistributedSimulationDriver2A".
  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. At this point these will mostly be 0, but can be a small positive integer.
  5. If you start up a VR-Forces application using DIS as the protocol, open a scenario, and then start the scenario, the number of PDUs read will increase notably, showing that a connection to the simulation has in fact been established by the driver.
  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 and byte counts are no longer being printed, and that the text "DistributedSimulationDriver::onStop():" has been printed on the subsequent line.
  8. Continually clicking the Start and Stop button will keep starting and stopping the driver, giving these same results in the console window.

[<< Introduction] [Create a Threaded Connection >>]


Project Files

DistributedSimulationDriver2A.h

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
class DtExerciseConn;
namespace makVrv
{
namespace tutorialDistributedSimulation2A
{
class DistributedSimulationDriver : public DtDriver
{
public:
DistributedSimulationDriver(DtAgentManager& agentManager, const std::string& instanceName);
virtual const std::string& className() const;
protected:
virtual bool onStart();
virtual bool onStop();
virtual bool onTick();
protected:
DtExerciseConn* myConnection;
};
}
}

DistributedSimulationDriver2A.cxx

// /******************************************************************************
// ** Copyright (c) 2011 MAK Technologies, Inc.
// ** All rights reserved.
// ******************************************************************************/
#define DtDIS 1
#include <vrvCore/DtDe.h>
#include <vl/exConnInit.h>
#include <iostream>
namespace makVrv
{
namespace tutorialDistributedSimulation2A
{
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;
DtExerciseConnInitializer init;
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);
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;
}
}
}

DistributedSimulationPlugin2A.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

DistributedSimulationPlugin2A.cxx

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <vrvCore/DtDe.h>
#include <boost/bind.hpp>
using namespace makVrv;
using namespace tutorialDistributedSimulation2A;
{
// We're done with the signal, so disconnect from it
de->signal_postInitialize.disconnect(boost::bind(
// Create the driver that will implement a distributed simulation
DistributedSimulationDriver* driver = new DistributedSimulationDriver(
de->agentManager(), "DistributedSimulationDriver2A");
// 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.
de.signal_postInitialize.connect(boost::bind(
}
}
{
// Setup the plugin. Normally, the init function and functionality
// should be in its own library.
init(*de);
return true;
}

Document ID: Generated on Tue Jan 29 18:21:16 EST 2013 from SVN revision 123193
Copyright © 2005-2013 VT MÄK Inc. All Rights Reserved (www.mak.com)