Cancel Fullscreen
Loading...
 

Programmers Guide

Wingman Framework Programmers Guide

Version 0.6.0
Date Updated : February 5th, 2016

INFO

Documentation in progress, not complete.


1. Introduction


This guide describes the Wingman Framework, and how to use Wingman facilities in the development of XPlane plugins. This guide covers the following topics.

  • XPlane Interface
  • Framework Basics
  • Build System
  • Debugging
  • Framework Usage

 

1.1. Purpose


The purpose of the Wingman Framework is to provide an easy to use API to develop plugins in an Object Orientated Programming,OOP, langauge.

1.2. Audience

This document is targeted to programmers who are writing XPlane plugins using the Wingman System, WMS. This system includes the myplugin template, Clamshell-VCCE, build system and the framework libraries.

1.3. Design Goals

The design goals for the framework is limit the overhead from the parent XPLM API while giving the programmer an Object Orientated Programming,OOP, design. Also to aid the developer to create XPlane plugins faster and for all targets XPlane supports.

1.4. Variants

   Each release of Wingman includes a debug and production versions of the linkable Framework Library for each target. Targets include

  • Windows 32bit
  • Windows 64bit
  • Linux 32bit
  • Linux 64bit


The debug variant of Wingman's framework library supports the output of debug messages while the production variant suppresses them. Some complex framework classes have debug level messages to aid the programmer with debugging and provides a class method to enable the output.  Also, when Wingman's build system with debug enabled then symbols are not stripped from the plugins binaries.

1.5. Framework Components


The below list of components and it's header files can be viewed from Wingman's framework include folder.
ex. "XPlane/Resources/Wingman/include/wingman/framework"

Component Description
base Base object and container list class.
common Common defines, enums, struct etc...
data Data and container list objects for XPLM Datarefs
exception Custom exception classes
gui 2D graphical user interface
graphics 3D drawing interface
interface Interface classes. (aka pure virtual classes)
io Input/Output classes for file and other communications.
location 2D and 3D coordinate system
message Internal communication system.
system External events and system processing
templates Template classes
utilities Commonly used classes and functions.
view 3D View classes.

 

1.6. References and Resources

 

 

2. XPlane Interface

 
The interface from Wingman to XPlane is via the XPlane Plugin Manager, XPLM. This XPLM supports XPlane 10.20 and newer for 32bit and 64bit platforms. XPlane 9 is not supported by Wingman. Interaction between XPLM and plugins is event, or callback, driven.
 

2.1. Plugin SDK


The XPlane Plugin SDK includes the XPLM 32bit and 64bit libraries and header files which provide a lower level C API to interface to the XPLM. The XPLM API is very well written, however it is written for procedural programming which can take more infrastructure to build a complex plugin.

2.2. Context


Context is what process or thread the plugin is running from. Preemptive vs cooperative and which one is the plugin running under. When designing your plugin you should design your tasking model under cooperative mythology. This means any events, callbacks, from XPLM the callback routine must run to completion. Any attempt to hold the context will lower XPlane's performance.
 

3. Framework Basics

 

3.1. Directory layout


Extracting the Wingman zip/tar.gz file revelas the below contents.

folder/files Description
3rdParty Any 3rdparty or contribution components.
include Framework include files.
lib Pre-built binaries of Wingman Framework for Windows and Linux in 32bit or 64bit and debug versions of those libraries.
sample Template project, source files located in there, called "myplugin"
XPSDK Pre-built low level XPLM libraries
License.txt License information for Wingman & location of where to find the EULA is kept in there.
ReleaseNotes.txt Information about the release.
rules.mk Make rules, required by Wingman's build system.
version.txt Version information. Need to know what version is installed, check this file.

 

3.2. Main


Every application requires a "main", somewhere where the application code starts, and under Wingman this is the class "PluginApplication". This class has an interface with 4 methods that handle the start, stop and communication.

Interface Description
Initialize() Method to initialize or create components
Start() Callback, after Initialize(), to start process events.
Stop() Called by XPLM when to stop your plugin.
Destroy() Called just before the plugin is unloaded from memory.

 

3.3. Header files

The Wingman Framework library consists of many header files with each one containing classes or functions. However only two header files are needed for plugin development.

  • wingman.h
  • xpsdk.h


The "wingman.h" includes all header files within the Wingman Framework Library. Just add this header file and all Wingman classes, typedefs, enumeration etc... will be included. This way any updates to the Wingman Framework header file locations and names will not impact you, just recompile and you are done.

The "xpsdk.h" includes all XPLM SDK header files as well as defines to compile against the XPLM SDK. You may need to include this file if you need to access the lower level XPLM API.

3.4. Namespace

The Wingman library is built under the namespace "wingman". This is to separate Wingman classes and functions from other libraries that may use the same names. Wingman definitions must be prefixed with "wingman::" otherwise the compiler will raise an error of unknown type.

For example: To declare an object of type XPWindow and instantiate

wingman::XPWindow *window = new wingman::XPWindow("winMain","Main Window");

However adding a "using namespace wingman" can eliminate the need to use the "wingman::" prefix.

#ifndef MYPLUGIN_H_
#define MYPLUGIN_H_
#include "wingman.h"

using namespace wingman;

For example: Add to the plugins header file.

#include "myplugin.h"

void Myplugin::Initialize()
{
  XPWindow *window = new XPWindow("winMain","Main Window");
}

The use of XPWindow no longer needs to be prefixed with "wingman::".

 

3.5. Short Paths

Short paths is a method to specify file paths within XPlane folders. This method allows plugins to define a file path that will work for all operating systems.

Short paths are used internally by Wingman. For example:

  • wingman.ini - To specify log and debug files.
  • xpcimage class - For loading PNG files.
  • configuration class - When creating your own INI configuration files.


Any methods with a string parameter named shortpath is expecting a shortpath.

Syntax: SHORTPATH | ["folders"]/filename"

The format of a short path is the SHORTPATH followed by a '|' and then directory names and finally a file. Directory and file names can be separated with either a backslash, '\', or forward slash, '/'.

SHORTPATH Description
PLUGIN The plugins root/home directory.
FAT Plugins executable directory. Under 64/ or 32/
EXEC XPlane's executable directory.
PREF XPlane's preference directory.
USER User defined. If you use then provide the full path as expected under the operating system. Caution, this will limit which operating system this plugin can load/save files.

 

3.6. Defines

Defines available when compiling.

define Description
OS_BITS Gives build type for the operating system, example 32 or 64 bits.
PLUGIN_VERSION Version string of the plugin version. This is the same as what is provided on the make command line make VERSION=x.y.z
DEBUG_ON If defined then the build has debug enabled. make DEBUG=ON
OS The Operating System from the make commandline , value will either be WIN32, WIN64, LINUX or MAC
OS_WINDOWS Will be defined if build is for a MS Windows Operating system
OS_LINUX Will be defined if build is for a Linux Operating system
OS_MAC Will be defined if build is for a Apple Mac Operating system

 

3.7. Events


Events are callbacks and callbacks are events, under the hood these are just function pointers. Where they differ is how they are used. A callback is called by a function/method to do some work and provide a result. An event is when something has happened in the system that requires attention or notification. Wingman utilizes a synchronous event model for internal events and external events. Internal events are events generated by the Wingman framework and external events are events that sent from outside of Wingmans framework. Since these events are synchronous they must all run to completion.

All Wingman classes that support events have a method to set a handler, only one event handler can be set for each object instance. Every set event handler method has an event wrapper where a reference to the instance of the class that hosts the handler is provided along with a reference of the class method that handles the event.

Example:

/* Setup the callback handler for when this timer expires */
priTimer->SetTimerEventHandler(TIMER_EVENT(&myplugin::timer_cb, myinstance))

TIMER_EVENT is the event wrapper.

&myplugin::timer_cb  - Is the class and method name that will handle the event

myinstance - Actual instance of myplugin class that will 

To clear an event handler simply pass in NULL to the handler parameter.

example:
priTimer->SetTimerEventHandler(NULL);

 

3.8. The wingman.ini

The wingman.ini file is a set of configuration parameters used by the Wingman framework.

When the plugin is initialized, Wingman will search for a wingman.ini file within the plugin's root directory and load it. If not found then one is created with default values.

Out of date wingman.ini files are upgraded automatically without reverting back to default values.

All file paths are in short path format. See section Short Paths.

Configuration Item Group Description
version VERSION The version of the wingman.ini file. Do not change.
verbose DEBUG Verbosity level to use for debug output. Only required if linked with the debug framework libraries.
output DEBUG Where to output the debug messages, XPlane's log.txt or plugins log file.
output_file DEBUG If output set to "FILE" then specify the file name of the plugins log file.
output LOG Where to output log messages, XPlane's log.txt or plugins log file.
output_file LOG If output set to "FILE" then specify the file name of the plugins log file.

 

4. Build System


The Make System builds, cleans and packages Wingman plugins. 

The system consists of the plugin's Makefile and a rules.mk file which is located in the Wingman folder.

Wingman folder includes a plugin template project, "examples/myplugin" to start developing and building using the Wingman build system.

 

4.1. Files and Directory Structure

The plugin template project includes the below folders and files.

File/Folder Re-distributable Description
src/
YES
Folder that contains source and header files
Doc/
YES
Folder to hold any documentation. This folder is re-distributable via build.conf
Resources/
YES
Folder to hold any loadable files by the plugin . This folder is re-distributable via build.conf
scripts/
YES
Scripts required during the build process.
build.conf
YES
Editable text file to configure how the plugin is built and distributed.
ChangeLog.txt
YES
Text file that includes a list of changes for each of the plugins releases.
README.txt
YES
A message to anyone using the plugin.
ReleaseNotes.txt
YES
A message to users of the plugin for the specific release
LICENSE.txt
YES
Text file that includes the software license of your plugin.
Makefile
YES
File read by Make that builds, cleans and packages the plugin.

 

4.2. Configuration

The plugin folder includes a file called "build.conf" which configures the plugins project info. This file is used by both the Makefile and package scripts. The build.conf contains the information on what to build but not how to build. The how to build is done in the rules.mk file which is included in the Wingman Framework folder.

Configuration Item default value Description
PLUGIN_NAME "myplugin" Set the name of your plugin project. This is used by the package creator to name the packages.
BUILD_TYPE PLUGIN Plugin build type - Do not change
INCLUDE_RESOURCES yes Include Resource Folder when creating a package
INCLUDE_DOCS yes Include Doc Folder when creating a package
INCLUDE_SOURCE no Include Source Code Folder when creating a package
INCLUDE_BUILD no Include Build System when creating a package
INCLUDE_LICENSE yes Include LICENSE.txt when creating a package
INCLUDE_README yes Include README.txt when creating a package
INCLUDE_CHANGELOG yes Include ChangeLog.txt when creating a package
INCLUDE_RELEASENOTES yes Include ReleaseNotes.txt when creating a package
INCLUDE_WM_INI no Include Wingman INI when creating a package
INCLUDE_ALL_INI no Include All INI files (*.ini) in the main folder when creating a package
INCLUDE_ALL_CONF no Include All conf files (*.conf) in the main folder when creating a package
CREATE_ZIP_PKG yes Create a zip distribution package
CREATE_TARGZ_PKG yes Creates a tar.gz distribution package

 

4.3. Adding Source Files

Adding source files is done by adding in your *.cpp and *.h/*.hpp into the src/ directory. The build system scans this directory for cpp files to compile.

4.4. Targets

There are three targets in the Wingman Make System

  • Building
  • Cleaning
  • Packaging

4.4.1. Building

Building is compiling and linking a plugin. There are three parameters that can be set on the make command line.

Syntax: make OS={OSTYPE} [DEBUG=ON] [VERSION={x.y.z}]

Example: make OS=WIN64 DEBUG=ON VERSION=1.0.0

Parameter Options Mandatory Description
OS WIN64, WIN32, LIN32, LIN64 YES Sets the target for the build.
DEBUG ON NO Links with the debug version of the framework and adds the DEBUG_ON define when compiling.
VERSION x.y.z NO Version format x= major, y=minor, z=build# - However any format can be used.

 

4.4.1. Cleaning

There are two targets related to cleaning; clean and distclean.

command OBJs XPL Package Description
clean
YES
NO
NO
Cleans up only object files.
distclean
YES
YES
YES
Cleans up everything.


Note: Make clean is required before building another OS target. If object files exist when building for another OS target the linker will raise an error of invalid format.

Example 1: make clean.
Example 2: make distclean
 

4.4.2. Packaging for distribution


After the plugin is built for one or more XPlane targets, calling "make package" will create a ZIP file and/or a tar.gz (tarball) file depending on the configuration set in build.conf.

Syntax: make package <version=x.y.z> </version=x.y.z>

The package will contain plugin binaries but can contain other files depending on the configuration set in build.conf.

5. Debugging

At this time, debugging plugins can be accomplished with output messages to either the XPlane log.txt file, to the plugins log file or WingmanOSS console by using the DEBUG_x output streams. See section Debug Output Streams for more info. 

To enable debugging, the plugin must be built with the DEBUG=ON parameter when calling Make.

Example 'make DEBUG=ON OS=WIN64'

Including the DEBUG=ON parameter includes symbol names into the plugin binary and links against the debug versions of the Wingman libraries. Also the debug verbosity level must be set to the highest level of output needed, this can be done in either the plugins wingman.ini file or from the WingmanOSS console.

6. Framework Usage 

 

6.1. Introduction

This section describes Wingman classes and how to use them in detail.

6.2. System

 

6.2.1. Output streams


Two output streams are supported, Logging and Debug messages.

 

6.2.1.1. Message Termination

Whether using LOG, SYSLOG or DEBUG streams, all messages that are to be outputed require a line end termination with WM_ENDL.

LOG_INFO << "3D Panel loaded" << WM_ENDL;

DEBUG_1 << "Line 1 was executed" << WM_ENDL;

The WM_ENDL macro is required only when you want to write the message to the output file.


If required, output can be delayed until full message can be created across multiple lines of code.

LOG_INFO << "Loading 3D Panel: ";


if (success)
   LOG_INFO << " Success" << WM_ENDL;
else
   LOG_INFO << " Failed" << WM_ENDL;


Will give the output depending on the value of "success".

0:0:0 [INFO](myplugin.applet) Loading 3D Panel: Success
or
0:0:0 [INFO](myplugin.applet) Loading 3D Panel: Failed

 

6.2.1.2. Logging


There are two types of logging classes, LOG and SYSLOG. Each type has several associated iostream class.


LOG classes by default write to XPlane's log file, however the log file and path can be change in the plugins wingman.ini file. These LOG classes should be used as this can help separate the plugins log messages from Xplane or other plugins.

class Description
LOG_INFO Informative message. Example would be something has loaded, a certain event was received etc...
LOG_WARN Warning the user of an event but system is still usable.
LOG_ERROR An error has occurred but system is still running but some features will not work.
LOG_FATAL A fatal error where the plugin needs to be shut down.


SYSLOG classes are always written to XPlane's log file and should be used only when necessary to always write the message to XPlanes log file. This would be more beneficial if what you have logged would help diagnose issues within XPlane.

class Description
SYSLOG_INFO Informative message. Example would be something has loaded, a certain event was received etc...
SYSLOG_WARN Warning the user of an event but system is still usable.
SYSLOG_ERROR An error has occurred but system is still running but some features will not work.
SYSLOG_FATAL A fatal error where the plugin needs to be shut down.


Example:

LOG_INFO << "Loading 3D Panel: " << WM_ENDL;
SYSLOG_INFO << "Always goes to Xplanes log.txt file " << WM_ENDL;
LOG_FATAL << "Fatal error" << WM_ENDL;


Format of a log message
{time stamp}{log type} {plugin.name} message

0:0:0 [INFO](myplugin.applet) Example of INFO
0:0:0 [WARNING](myplugin.applet) Example of WARNING
0:0:0 [ERROR](myplugin.applet) Exmaple of ERROR
0:0:0 [FATAL](myplugin.applet) Example of FATAL

 

6.2.1.3. Debug


 Debug messages by default are written in to XPlane's log file. However this can be changed so debug messages are written to the plugins own debug file or in the plugins own log file. There are a maximum of 4 verbosity levels. See section wingman.ini

Debug messages are only enabled when the plugin is linked against the debug version of the wingman library.

Debug verbosity level can be changed in the plugins wingman.ini file or using WingmanOSS. The difference between these two is if changing the level in wingman.ini then the plugin will need to be restarted for the change to take effect. However if using WingmanOSS via the console then the verbosity level can be changed while the plugin is running.

 

class Description
DEBUG_1 Level 1 verbosity
DEBUG_2 Level 2 verbosity
DEBUG_3 Level 3 verbosity
DEBUG_4 Level 4 verbosity


Format of a log message
{time stamp}{DEBUG_x} {plugin.name} message

0:0:0 [DEBUG_1](wingman.myplugin) My debug level 1 message
0:0:0 [DEBUG_2](wingman.myplugin) My debug level 2 message
0:0:0 [DEBUG_3](wingman.myplugin) My debug level 3 message
0:0:0 [DEBUG_4](wingman.myplugin) My debug level 4 message


When the plugin is not linked against the debug version of Wingman Framework Library then all calls to DEBUG_x classes are redirected to NULL streams.

INFO

When setting the verbosity level, a value of 0, zero, disables all output from the DEBUG_x class streams.

 

6.2.2. Timers


Wingman supports Event Timers, which are timers that expire will send a event to registered handlers.

6.2.2.1. Event Timers


Event timers are supported using XPlanes FlightLoop. Wingman's event timers are based on a precision timer algorithm.

There are two types of event timers: Continuous and OneShot.

Continuous timers, when started, will continue to run and send the expire event until the timer is instructed to be stopped.

Oneshot timers, shen started, will only give one expiration event and must be restarted if another event is required.


The precision timer framework supports two models of operations; Precise and Estimate.

At this time only the Precise model is implemented which provides the highest accuracy but uses the most amount of CPU cycles.

At this time, the Estimate model is not been implemented but will give the lowest accuracy and lower amount of CPU cycles.

No matter what the timer model is set to, the accuracy depends on what XPlane is doing. If the simulator is slow, either due to CPU limitation or low FPS then the timer accuracy will only be as good as when XPlane can call Wingmans timer backend. But no matter which model is selected, Wingman will call your event callback at the most precise time it can.


The below code snippets comes from the WingmanDemo1 source code, under the TimerDialog.cpp.
This will execute the timer_cb method every second using the TimerContinuous class.

void myplugin::timer_cb(PrecisionTimer &timer, float delta, float timestamp)
{
 LOG_INFO << "Continuous Timer expired" << WM_ENLD;
}

/* A PrecisionTimer can be either a TimerContinuous or TimerOneShot objects */
PrecisionTimer  *priTimer;

/* Create new Continuous timer object and set the default timeout to 1000ms */
priTimer = new TimerContinuous("tmrEvent", 1000);

/* Setup the callback handler for when this timer expires */
priTimer->SetTimerEventHandler(TIMER_EVENT(&myplugin::timer_cb, this));

/* Set the interval to 1 second or 1000ms
priTimer->SetInterval(1000);

/* Adding the timer object to the Timer subsystem will start the timer */
Timer::Add(priTimer);


This will execute the timer_cb only once after 1 second using the TimerOneShot class.

void myplugin::timer_cb(PrecisionTimer &timer, float delta, float timestamp)
{
 LOG_INFO << "OneShot Timer expired" << WM_ENLD;
}

/* A PrecisionTimer can be instantiated as either a TimerContinuous or TimerOneShot objects */
PrecisionTimer  *priTimer;

/* Create new OneShot timer object and set the default timeout to 1000ms */
priTimer = new TimerOneShot("tmrEvent", 1000);

/* Setup the callback handler for when this timer expires */
priTimer->SetTimerEventHandler(TIMER_EVENT(&myplugin::timer_cb, this));

/* Set the interval to 1 second or 1000ms
priTimer->SetInterval(1000);

/* Adding the timer object to the Timer subsystem will start the timer */
Timer::Add(priTimer);

 

6.2.3. Process Events


Process Events is the base class that handles all external events, for example events sent from XPlane.

6.2.3.1. Interface

ProcessEvents class ueses the IProcess and IControl interfaces. IProcess is a single method called by to process when the process event is called, this method takes no parameters and returns no vlaue. IControl provides the interface to start, stop and reset the object.

The ProcessEvent manages a list of DataObjects and has properties to control direct reads and writes to that list.

CheckWriteProtect() method is used as a flag to skip over all data writes. This is useful to save CPU cycles when there are no data objects that need to be written.

6.2.3.2. XPLM Flight Loop

This class handles the basic XPLM flight loop, default is called for every frame unless a value is specified in the SetInterval method.  

SetInterval takes a value that is divisble by 1000, 1 second. If you want the next flight loop event to be called every 2 seconds then it will be "SetInterval(2000)". To get called every frame pass in a value of -1.

Graphic showing DirectReads, Flight Loop Event, DirectWrites for DataRefs.

The FlightLoops default process method calls DirectRead on all DataRef objects assigned to the DataObject manager before calling the flight loop event. When the flight loop event returns, the process method takes care of any DirectWrites for DataRef objects that are not set  with write protect on.

To begin receiving FlightLoop events, Instantciate a FlightLoop object, set the FlightLoopEventHandler,  set the interval then finally call the Start() method.

Within the flight loop event handler, SetInterval() can be called to change when the next interval dynamically. Also, within the flight loop event handler, Stop() can be called to stop receiving events. Start() may be called to start receiving events again.

 

7. Appendix

6.3. Abbreviations

 

Abbreviation Description
API Application Programming Interface
OOP Object Oriented Programming
SDK Software Development Kit
WMS Wingman System
XPLM X-Plane Plugin Manager