MAK Data Logger API Documentation for HLA
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
2 - The Logger Architecture

Table of Contents

The Logger architecture is highly modular and designed to be independent of the simulation protocol, user interface, and execution type (it supports both iterative or multi-threaded).

Every functional module in the Logger has a driver, a factory and an interface. The factory defines the commands that can be sent to the driver and the responses the driver sends back to the interface. The interface provides a way to send the commands and receive the responses. The driver receives the commands, acts upon them, and sends responses if necessary. The stateObserver plug-in example shows how to implement a driver, factory, and interface.

The Logger also has a message pipeline that is controlled by various drivers (only one at a time). The pipeline takes messages from an input stage, moves them through the state stage, and sends them out of the output stage. For example, the playback driver reads a file during the file input stage and sends the data to a simulation over a network during the simulation output stage.

2.1 Drivers

The base class of drivers that act on commands is DtLgrCommandHandler (lgrDriver.h). This class provides the ability to receive and respond to commands from the DtLgrSystemDriver (lgrSystemDriver.h). To connect a command to a function in the driver use the addCommandHandler() function. Member functions are usually connected using a functor object in the driver’s constructor. Depending on the operation, a driver may request access to the pipeline (if another driver currently owns the pipeline it is notified and can perform any necessary operations to release the pipeline or reject the request). The driver’s tick() member function is called regularly by DtLogger, which executes any submitted commands. An example of a driver class is DtLgrPlaybackDriver (lgrPlaybackDriver.h). For an example of how to write a driver see stateObModel.h and stateObModel.cxx in the stateObserver example.

2.2 Factories

The factory class provides static functions for defining, creating, and decoding commands. Each command has three functions – a define function, a create function, and a decode function. The command definition function returns a DtCommandDefinition (lgrRuntimeCommandFactory.h) object, which defines the name of the command, its type, and its parameters. This definition is used by the drivers to register command handlers and by the runtime command factory, which parses commands from strings (typically originating from an input console). The create() function takes the necessary parameters and returns a DtCommand (lgrCommand.h) object. The decode() function takes a DtCommand object and decodes its parameters. If the parameters or type of the DtCommand object are not correct for the specific command, an exception is thrown. This indicates an error in the create function or in the command handlers. Similarly, there are create functions and decode functions for responses (there is no definition function). An example of a factory class is DtLgrPlaybackCommandFactory, in lgrPlaybackCommandFactory.h.

A factory class is not strictly necessary. However, it provides a clear distinction between the definition of a command and the implementation of the command handler. Any class, including the driver or the interface, can contain the functions for defining, creating, and decoding a command object. Utility C++ macros for declaring the necessary static command functions are provided in lgrCommand.h.

2.3 Interfaces

The interface classes provide a simplified method for sending commands and receiving responses. Each interface maintains a local state, which is updated via the responses. Interfaces are designed to be thread-safe and are used to communicate across thread boundaries. They are also safe to construct in separate threads, because the Logger is locked when it creates interfaces. Interfaces must be updated regularly to process queued responses. This is very important, because only one DtResponse is created and shared across all interfaces. If an interface does not call update() the response will remain in its queue and never be deallocated. Please see playTape.cxx and writeTape.cxx for examples of how to use interface classes. If you need to use several interfaces of different types, use an instance of DtLgrFullInterface, which contains several interfaces.

An example of an interface class is DtLgrPlaybackInterface, in lgrPlaybackInterface.h.

The DtStateObserverController in stateObController.h and stateObController.cxx uses a base DtCommandInterface object, rather than subclassing it specifically for the state observer commands. Commands are submitted manually and callbacks are added for specific responses. This is easier for very small interfaces. However, once an application has several commands and responses, it is preferable to organize it as a full sub-class, which hides these details when using the interface.

2.4 The Logger Message Pipeline

The Logger pipeline has three major stages – the input stage, the state stage, and the output stage. Each stage is highly configurable and largely independent of each other. Depending on the mode of operation, different objects are added to and removed from the pipeline. For example during recording a DtSimInput acquired by the simulation manager does the following:

  1. Reads data from the network.
  2. Sends the data to the state stage, which maintains the state of the simulation internal to the Logger.
  3. Sends the data to the output stage, which in this case is a file write object, which writes the data to a file.

2.4.1 The Input Stage

The input interface is defined by DtMessageInput (messageInput.h). For simulation input, the DtLgrSimInput class (lgrSimInput.h) provides a common interface for input from a live simulation. The primary purpose of the input interface is to retrieve messages over time.

2.4.2 The State Stage

The state interface is defined by DtMessageState (messageState.h). It has derived classes specific to each supported protocol. The state stage stores the state of persistent objects in a network-independent format. It can generate the messages needed to store the entire state of the simulation as a checkpoint.

2.4.3 The Output Stage

The output interface is defined by DtMessageOutput (messageOutput.h). The derived class DtLgrSimOutput (lgrSimOutput.h) provides a common interface for output to a live simulation.

2.5 The Simulation Manager

The simulation manager (DtLgrBaseSimManager) (lgrBaseSimManager.h) and its sub classes (DtLgrDisSimulationManager (lgrDisSimManager.h), DtLgrHlaSimulationManager (lgrHlaSimManager.h), and so on) provide simulation management when connected to a distributed simulation. The simulation manager constructor must be defined by the DtLgrProtocolRegistration (lgrProtocolRegistration.h) implementation, which is required for the DtLogger to function. The simulation manager is responsible for maintaining all simulation specific objects such as publishers and the necessary callbacks. It also provides access to creating simulation-specific objects, such as the simulation input and output stages, and opens files for a specific format.

[<< Introduction] [Home] [Top of Page] [Embedding the Logger in an Application >>]


Document ID: Generated on Thu Dec 18 15:35:09 EST 2025 from SVN revision 282494
Copyright © 2024 MAK Technologies. All Rights Reserved (www.mak.com)