Data Source PluginsOne of the four types of plugins available to VisualCommander, Data Source Plugins provide new ways of getting data into VisualCommander. The possibilities are endless: a Data Source Plugin could run simulations, control test hardware, retrieve data from the internet or command remote systems. The end user can create whatever plugin is necessary to fulfill their needs and be assured that VisualCommander's visualization tools can be leveraged to help manage it.
This page explains how to write data source plugins showing an interface for a Saitek X52 Flight Control System.
Data source plugins are used to input data in VisualCommander. Data can be generated by the plugin, come from an external source such as a data aquisition device, or from another software package.
The first step is to open XCode and select new project. Scroll through the template list and find VisualCommander. Select "Data Source". This will give you working code which you can modify to make your data source. Name it and select its location.
Build the project. It should build without error.
This example is for a plugin to read from a Saitek X52 flight controller. This uses a C library. C headers are included as extern "C". You can include any C libraries or C++ libraries you choose into the plugin.
extern "C" {
#include "HIDInput.h"
}
This library has 2 functions. One initializes the Human Interface Device (HID) and the other polls the outputs of the joystick. The first is called in the initialization method. This is necessary to initialize an HID interface. This is where you do one time initialization calls to your data source code.
bool VCHIDSource::initialize()
{
// HID calls
saitekInitialized = InitializeHIDManager();
if( !saitekInitialized )
return false;
else
return true;
}
The next method that needs to be modified is to create the outputs from the plugin to VC. The C library containts the name of each element (button, switch, etc.) on the Saitek. We read out the name and then define a point for each. Since we know the maximum size of the names of the Saitek output elements we can just use a C array of size 100 as a buffer. All outputs are integers so we declare them all as sd_type_int. The string c will appear as a data source.
If the the Saitek isn't plugged in this routine will produce a set of empty elements. The HID: prefix will organize the outputs so that they all appear in the category HID. When defining a point the first argument is the name, the second is the type (in this case integer), the third is a character string for the units and the last a comment string for the description.
bool VCHIDSource::setup_metadata()
{
const char *s;
const char *d;
char c[100];
if( !saitekInitialized ) return false;
for( int k = 0; k < NUMBER_OF_ELEMENTS; k++ )
{
s = GetElementName(k);
d = GetElementDescription(k);
strcpy( c, "HID:");
strcat( c, s );
id[k] = define_point(c, sd_type_int,"",d);
}
metadata_complete();
return true;
}
The other piece of bookkeeping we have to do is to declare some information for VC describing the plugin
extern "C" void *vc_plugin_description()
{
void *ret = VCDataSourceDescription("com.psatellite.HIDSource","HID","Acquires data from a Saitek X52 Flight Control System.",false,false);
return ret;
}
During operation of this plugin the plugin stays in the run_source method. This method interacts with VC and handles all VC commands sent to the plugin.
void VCHIDSource::run_source()
{
for (;;)
{
if (stage() != VCDataSourceRunning)
{
// Nothing to do except handle messages and continue
ds_date stop;
stop += ds_time_interval(1.0);
handle_messages(&stop);
continue;
}
if (stage() != VCDataSourceRunning) continue;
bool complete = false;
// Need to actually run the system
struct timeval next_loop;
ds_date now;
gettimeofday(&next_loop,NULL);
next_loop.tv_sec+=1;
extract_data_and_send();
ds_date stop(next_loop);
do
{
handle_messages(&stop);
} while (ds_date()
The utility method extract_data_and_send() polls the Saitek joystick and loads the
data into the VC interface.
void VCHIDSource::extract_data_and_send()
{
int joystickData[NUMBER_OF_ELEMENTS];
if( !saitekInitialized ) return;
// Call HID for the new data
GetSaitekOutput( joystickData );
// Load into the VisualCommander interface
for( int k = 0; k < NUMBER_OF_ELEMENTS; k++ )
{
store_data(id[k], &joystickData[k]);
}
send_data(ds_time_record());
}