Avidyne Homepage
Forum Home Forum Home > Avidyne General > IFD 5 Series & IFD 4 Series Touch Screen GPS/NAV/COM
  New Posts New Posts RSS Feed - IFD XP Trainer (Distance to wpt and FLT PLN sync)
  FAQ FAQ  Forum Search   Register Register  Login Login

IFD XP Trainer (Distance to wpt and FLT PLN sync)

 Post Reply Post Reply
Author
Message
ricardo View Drop Down
Senior Member
Senior Member


Joined: 17 Jan 2022
Location: Seattle, wa
Status: Offline
Points: 139
Post Options Post Options   Thanks (0) Thanks(0)   Quote ricardo Quote  Post ReplyReply Direct Link To This Post Topic: IFD XP Trainer (Distance to wpt and FLT PLN sync)
    Posted: 14 Dec 2024 at 5:18pm
I was futzing around with the SDK a few months back, wanting to fix 2 things that bug me about the IFD XPlane Trainer.

1 - The distance to next waypoint is not set by the IFD XP, so if you are using a G5 instrument, you dont get the distance to next Waypoint annuciated properly on the instrument. (on the HSI)

2 - It does not have a mode to copy the flight plan to the NAV1 GPS.. - whether its a GNS 430 or other.

So i went ahead and used the Avidyne SDK and the XPlane plugin SDK and wrote a plugin to do both of these things.

I dont have the proper motivation to compile this plugin and make it available for download (I do personally use it on my own XPlane), so i'll just paste the code that i wrote to do this, in case someone else finds it useful and/or wants to clean it up and make it more widely available.

i'd say it mostly works. -- I am using this plugin on my own training with XPlane at home.

======================================================

#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <vector>

#include "XPLMProcessing.h"
#include "XPLMDataAccess.h"
#include "XPLMUtilities.h"
#include "XPLMPlugin.h"
#include "XPLMNavigation.h"

#include "avisdk/Tier1/FlightData/flightData.h"
#include "avisdk/Tier1/FlightData/Waypoint.h"
#include "avisdk/UtilityClasses/AviCaps.h"
#include "avisdk/Tier2/Crc32Bit.h"

static XPLMDataRef gEnabledDataRef = NULL;
static XPLMDataRef gConnectedDataRef = NULL;
static XPLMDataRef gUpdateRateSecDataRef = NULL;
static XPLMDataRef gFlightPlanSizeDataRef = NULL;
static XPLMDataRef gFlightPlanHashDataRef = NULL;
static XPLMDataRef gGpsDmeDistanceNmDataRef = NULL;
static XPLMDataRef gOverrideGpsDataRef = NULL;

static XPLMDataRef gSyncDistanceToNextWptDataRef = NULL;
static XPLMDataRef gDistanceToNextWptDataRef = NULL;

static XPLMDataRef gSyncFlightPlanToGPS1DataRef = NULL;
static XPLMDataRef gSuspendOverrideGpsDataRef = NULL;

static bool gEnabledValue = true;
static void SetEnabledDataRefCB(void* inRefCon, int value);
static int GetEnabledDataRefCB(void* inRefCon);

static bool gConnectedValue = false;
static int GetConnectedDataRefCB(void* inRefCon);

static float gUpdateRateSecValue = 2.0;
static void SetUpdateRateSecDataRefCB(void* inRefCon, float value);
static float GetUpdateRateSecDataRefCB(void* inRefCon);

static int gFlightPlanSizeValue = 0;
static int GetFlightPlanSizeDataRefCB(void* inRefCon);

static unsigned int gFlightPlanHashValue = 0;
static int GetFlightPlanHashDataRefCB(void* inRefCon);

static bool gSyncDistanceToNextWptValue = true;
static void SetSyncDistanceToNextWptDataRefCB(void* inRefCon, int value);
static int GetSyncDistanceToNextWptDataRefCB(void* inRefCon);

static double gDistanceToNextWptValue = 0.0;
static double GetDistanceToNextWptDataRefCB(void* inRefCon);

static bool gSyncFlightPlanToGPS1Value = true;
static void SetSyncFlightPlanToGPS1DataRefCB(void* inRefCon, int value);
static int GetSyncFlightPlanToGPS1DataRefCB(void* inRefCon);

static bool gSuspendOverrideGpsValue = false;
static void SetSuspendOverrideGPSDataRefCB(void* inRefCon, int value);
static int GetSuspendOverrideGPSDataRefCB(void* inRefCon);

static long gGenerationCounter = 0;

static AviSdk::AviCaps ifd;
static AviSdk::flightData fpl_monitor; 
static AviSdk::Waypoint* gWaypoints = nullptr;

static float TimedCallback(
float                inElapsedSinceLastCall,
float                inElapsedTimeSinceLastFlightLoop,
int                  inCounter,
void* inRefcon);

typedef unsigned int CRC32;

void LOG(const char* format, ...) {
char timestamp[16];
time_t ltime;
ltime = time(NULL);
struct tm* tm;
tm = localtime(&ltime);
sprintf(timestamp, "%04d%02d%02d%02d%02d%02d", tm->tm_year + 1900, tm->tm_mon,
tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);

char message[256];
va_list args;
va_start(args, format);
vsprintf(message, format, args);
va_end(args);

XPLMDebugString(timestamp);
XPLMDebugString(": ");
XPLMDebugString(message);
XPLMDebugString("\n");
}

CRC32 GetFlightPlanHash(std::vector<AviSdk::Waypoint>& waypoints) {
::AviSdk::Crc32Bit crc;
crc.Reset();
for (AviSdk::Waypoint& wp : waypoints) {
crc.Add((const unsigned char *)wp.getID(), strlen(wp.getID()));
if (wp.isActive()) {
crc.Add((const unsigned char *)"active", 6);
}
}
return crc.Value();
}

PLUGIN_API int XPluginStart(
char * outName,
char * outSig,
char * outDesc) {
strcpy(outName, "AviSync");
strcpy(outSig, "xplanesdk.examples.timedprocessing");
strcpy(outDesc, "A plugin to copy IFD FPL Data to the onboard FMS.");
/* Find the data refs we want to record. */
gEnabledDataRef = XPLMRegisterDataAccessor("avidyne/ifd/plugin_enabled",
xplmType_Int, 1,
GetEnabledDataRefCB, SetEnabledDataRefCB,
NULL, NULL,                                    // Float accessors
NULL, NULL,                                    // Double accessors
NULL, NULL,                                    // Int array accessors
NULL, NULL,                                    // Float array accessors
NULL, NULL,                                    // Raw data accessors
NULL, NULL);
gConnectedDataRef = XPLMRegisterDataAccessor("avidyne/ifd/connected",
xplmType_Int, 0,
GetConnectedDataRefCB, NULL, 
NULL, NULL,                                    // Float accessors
NULL, NULL,                                    // Double accessors
NULL, NULL,                                    // Int array accessors
NULL, NULL,                                    // Float array accessors
NULL, NULL,                                    // Raw data accessors
NULL, NULL);
gUpdateRateSecDataRef = XPLMRegisterDataAccessor("avidyne/ifd/update_rate_sec",
xplmType_Float, 1,
NULL, NULL,                                    // Int accessors
GetUpdateRateSecDataRefCB, SetUpdateRateSecDataRefCB,
NULL, NULL,                                    // Double accessors
NULL, NULL,                                    // Int array accessors
NULL, NULL,                                    // Float array accessors
NULL, NULL,                                    // Raw data accessors
NULL, NULL);
gFlightPlanSizeDataRef = XPLMRegisterDataAccessor("avidyne/ifd/flight_plan_size",
xplmType_Int, 0,
GetFlightPlanSizeDataRefCB, NULL,
NULL, NULL,                                    // Float accessors
NULL, NULL,                                    // Double accessors
NULL, NULL,                                    // Int array accessors
NULL, NULL,                                    // Float array accessors
NULL, NULL,                                    // Raw data accessors
NULL, NULL);
gFlightPlanHashDataRef = XPLMRegisterDataAccessor("avidyne/ifd/flight_plan_hash",
xplmType_Int, 0,
GetFlightPlanHashDataRefCB, NULL,
NULL, NULL,                                    // Float accessors
NULL, NULL,                                    // Double accessors
NULL, NULL,                                    // Int array accessors
NULL, NULL,                                    // Float array accessors
NULL, NULL,                                    // Raw data accessors
NULL, NULL);
gSyncDistanceToNextWptDataRef = XPLMRegisterDataAccessor("avidyne/ifd/sync_distance_to_next_wpt",
xplmType_Int, 1,
GetSyncDistanceToNextWptDataRefCB, SetSyncDistanceToNextWptDataRefCB,
NULL, NULL,                                    // Float accessors
NULL, NULL,                                    // Double accessors
NULL, NULL,                                    // Int array accessors
NULL, NULL,                                    // Float array accessors
NULL, NULL,                                    // Raw data accessors
NULL, NULL);
gDistanceToNextWptDataRef = XPLMRegisterDataAccessor("avidyne/ifd/distance_to_next_wpt",
xplmType_Float, 0,
NULL, NULL,    // Int accessors
NULL, NULL,    // Float accessors
GetDistanceToNextWptDataRefCB, NULL,           // Double accessors
NULL, NULL,                                    // Int array accessors
NULL, NULL,                                    // Float array accessors
NULL, NULL,                                    // Raw data accessors
NULL, NULL);
gSyncFlightPlanToGPS1DataRef = XPLMRegisterDataAccessor("avidyne/ifd/sync_flight_plan_to_gps_1",
xplmType_Int, 1,
GetSyncFlightPlanToGPS1DataRefCB, SetSyncFlightPlanToGPS1DataRefCB,
NULL, NULL,                                    // Float accessors
NULL, NULL,                                    // Double accessors
NULL, NULL,                                    // Int array accessors
NULL, NULL,                                    // Float array accessors
NULL, NULL,                                    // Raw data accessors
NULL, NULL);
gSuspendOverrideGpsDataRef = XPLMRegisterDataAccessor("avidyne/ifd/suspend_override_gps",
xplmType_Int, 1,
GetSuspendOverrideGPSDataRefCB, SetSuspendOverrideGPSDataRefCB,
NULL, NULL,                                    // Float accessors
NULL, NULL,                                    // Double accessors
NULL, NULL,                                    // Int array accessors
NULL, NULL,                                    // Float array accessors
NULL, NULL,                                    // Raw data accessors
NULL, NULL);

gGpsDmeDistanceNmDataRef = XPLMFindDataRef("sim/cockpit2/radios/indicators/gps_dme_distance_nm");
gOverrideGpsDataRef = XPLMFindDataRef("sim/operation/override/override_gps");

XPLMRegisterFlightLoopCallback(TimedCallback, 1.0, NULL);
return 1;
}

PLUGIN_API void XPluginStop(void)
{
XPLMUnregisterDataAccessor(gEnabledDataRef);
XPLMUnregisterDataAccessor(gConnectedDataRef);
XPLMUnregisterDataAccessor(gUpdateRateSecDataRef);
XPLMUnregisterDataAccessor(gFlightPlanSizeDataRef);
XPLMUnregisterDataAccessor(gFlightPlanHashDataRef);
XPLMUnregisterDataAccessor(gSyncDistanceToNextWptDataRef);
XPLMUnregisterDataAccessor(gDistanceToNextWptDataRef);
XPLMUnregisterDataAccessor(gSyncFlightPlanToGPS1DataRef);
XPLMUnregisterDataAccessor(gSuspendOverrideGpsDataRef);

XPLMUnregisterFlightLoopCallback(TimedCallback, NULL);
}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API int XPluginEnable(void)
{
return 1;
}

PLUGIN_API void XPluginReceiveMessage(
XPLMPluginID inFromWho,
int inMessage,
void * inParam)
{
}

void SetEnabledDataRefCB(void* inRefCon, int value) {
gEnabledValue = value;
}

int GetEnabledDataRefCB(void* inRefCon) {
return gEnabledValue;
}

int GetConnectedDataRefCB(void* inRefCon) {
return gConnectedValue;
}

void SetUpdateRateSecDataRefCB(void* inRefCon, float value) {
gUpdateRateSecValue = value;
}

float GetUpdateRateSecDataRefCB(void* inRefCon) {
return gUpdateRateSecValue;
}

int GetFlightPlanSizeDataRefCB(void* inRefCon) {
return gFlightPlanSizeValue;
}

int GetFlightPlanHashDataRefCB(void* inRefCon) {
return gFlightPlanHashValue;
}

static void SetSyncDistanceToNextWptDataRefCB(void* inRefCon, int value) {
gSyncDistanceToNextWptValue = value;
}

static int GetSyncDistanceToNextWptDataRefCB(void* inRefCon) {
return gSyncDistanceToNextWptValue;
}

static double GetDistanceToNextWptDataRefCB(void* inRefCon) {
return gDistanceToNextWptValue;
}

static void SetSyncFlightPlanToGPS1DataRefCB(void* inRefCon, int value) {
gSyncFlightPlanToGPS1Value = value;
gFlightPlanHashValue = 0;
}

static int GetSyncFlightPlanToGPS1DataRefCB(void* inRefCon) {
return gSyncFlightPlanToGPS1Value;
}

static void SetSuspendOverrideGPSDataRefCB(void* inRefCon, int value) {
gSuspendOverrideGpsValue = value;
}

static int GetSuspendOverrideGPSDataRefCB(void* inRefCon) {
return gSuspendOverrideGpsValue;
}

float TimedCallback(
float                inElapsedSinceLastCall,
float                inElapsedTimeSinceLastFlightLoop,
int                  inCounter,
void* inRefcon) {
// LOG("TimedCallback(): Enter");
// LOG("TimedCallback(): Counter: %d", inCounter);

if (!gEnabledValue) {
// LOG("TimedCallback(): Plugin not enabled.");
return 5.0;
}

if (gConnectedValue) {
if (gSyncFlightPlanToGPS1Value && gSuspendOverrideGpsValue) {
gGenerationCounter += 1;
}

// LOG("TimedCallback(): Already connected to IFD");
if (fpl_monitor.Update()) {
// LOG("TimedCallback(): Update from IFD received");

if (gSyncDistanceToNextWptValue) {
gDistanceToNextWptValue = fpl_monitor.get_DistanceToWpt();
XPLMSetDataf(gGpsDmeDistanceNmDataRef, gDistanceToNextWptValue);
// LOG("TimedCallback(): Distance to next wpt: %f", gDistanceToNextWptValue);
}

if (gSyncFlightPlanToGPS1Value) {
std::vector<AviSdk::Waypoint> waypoints = fpl_monitor.get_FlightPlan();
CRC32 hash = GetFlightPlanHash(waypoints);
if (gFlightPlanHashValue != hash) {
gFlightPlanSizeValue = waypoints.size();
gFlightPlanHashValue = hash;

// LOG("TimedCallback(): Found an IFD FP with %d waypoints", waypoints.size());

int count = XPLMCountFMSEntries();
for (int index = 0; index < count; index++) {
XPLMClearFMSEntry(index);
}

for (AviSdk::Waypoint& wp : waypoints) {
// LOG("TimedCallback(): WP: %d ID:%s LAT:%f LON:%f %s",
// wp.getSequence(), wp.getID(), wp.getWayLat(),
// wp.getWayLon(), wp.isActive() ? "ACTIVE" : "");
float lat = wp.getWayLat();
float lon = wp.getWayLon();
XPLMNavRef nav_ref = XPLM_NAV_NOT_FOUND;
std::vector< XPLMNavType> nav_types{
xplm_Nav_Airport, xplm_Nav_NDB, xplm_Nav_VOR, xplm_Nav_ILS, xplm_Nav_Localizer,
xplm_Nav_GlideSlope, xplm_Nav_OuterMarker, xplm_Nav_MiddleMarker, xplm_Nav_InnerMarker,
xplm_Nav_Fix, xplm_Nav_DME };
for (XPLMNavType nav_type : nav_types) {
nav_ref = XPLMFindNavAid(NULL, wp.getID(), &lat, &lon, NULL, nav_type);
if (nav_ref != XPLM_NAV_NOT_FOUND) {
char nav_id[256];
XPLMGetNavAidInfo(nav_ref, NULL, NULL, NULL, NULL, NULL, NULL, nav_id, NULL, NULL);

if (strcmp(wp.getID(), nav_id) != 0) {
// LOG("TimedCallback(): Nav overriden to NOT FOUND");
nav_ref = XPLM_NAV_NOT_FOUND;
continue;
}
break;
}
// LOG("TimedCallback(): WP is not a nav aid of type: %d", nav_type);
}

if (nav_ref == XPLM_NAV_NOT_FOUND) {
// LOG("TimedCallback(): WP not found in database");
XPLMSetFMSEntryLatLon(wp.getSequence() - 1, wp.getWayLat(), wp.getWayLon(), 1000);
// LOG("TimedCallback(): WP added as LAT LON");
}
else {
XPLMSetFMSEntryInfo(wp.getSequence() - 1, nav_ref, 0);
// LOG("TimedCallback(): WP added to FMS");
}
if (wp.isActive()) {
XPLMSetDestinationFMSEntry(wp.getSequence() - 1);
// LOG("TimedCallback(): WP set as active on FMS");
}
}
}
}
} else {
// LOG("TimedCallback(): No new data from IFD");
}

// Disable the GPS override for 1 cycle, every 10 cycles.
// This was an experiment I was doing to see if i can get the GNS430 map to update properly
// even when the Avidyne XPlane Trainer has taken over the GPS -- half baked at this point.
if (gSyncFlightPlanToGPS1Value && gSuspendOverrideGpsValue) {
if ((gGenerationCounter % 10) == 0) {
XPLMSetDatai(gOverrideGpsDataRef, 0);
} else if (XPLMGetDatai(gOverrideGpsDataRef) == 0) {
XPLMSetDatai(gOverrideGpsDataRef, 1);
}
}

} else {
LOG("TimedCallback(): Looking for IFD...");
gConnectedValue = ifd.Update() && ifd.IsConnected();
if (gConnectedValue && !ifd.IsSDKVerOK()) {
LOG("TimedCallback(): SDK Version mismatch");
LOG("TimedCallback(): Exit Abnormal");
return 0;
}

if (gConnectedValue) {
LOG("TimedCallback(): IFD Found");
fpl_monitor.Init(ifd.GetIpAddr());
LOG("TimedCallback(): FPL Monitor Initialized");
}
}

/* Call us back in a few seconds */
// gUpdateRateMillisValue = gConnectedValue ? fpl_monitor.GetUpdateRate() : ifd.GetUpdateRate();
// gUpdateRateMillisValue = gUpdateRateMillisValue < 1000.0 ? 1000.0 : gUpdateRateMillisValue;
// LOG("TimedCallback(): Requesting callback in %f seconds", gUpdateRateSecValue);
// LOG("TimedCallback(): Exit Normal");
return gUpdateRateSecValue;
}                                   

======================================================


Edited by ricardo - 14 Dec 2024 at 5:20pm
Back to Top
Melohn View Drop Down
Senior Member
Senior Member
Avatar

Joined: 11 Dec 2013
Location: PHNL
Status: Offline
Points: 150
Post Options Post Options   Thanks (0) Thanks(0)   Quote Melohn Quote  Post ReplyReply Direct Link To This Post Posted: 14 Dec 2024 at 8:13pm
It would be great if you would consider also posting the compiled plugin for X-plane users to use. Windows version would be most helpful. Only a small number of people have the SDK.

I’m also interested in your “half baked” idea to pause control of the sim to allow for example the ID function on the IFD Trainer to identify the tuned navaid; this is very useful when simulating an ILS or VOR approach. It’s easy enough to remember to switch the Nav source to VLOC, but switching back on a missed approach works less than half of the time, at least for me.





Edited by Melohn - 14 Dec 2024 at 8:20pm
Back to Top
ricardo View Drop Down
Senior Member
Senior Member


Joined: 17 Jan 2022
Location: Seattle, wa
Status: Offline
Points: 139
Post Options Post Options   Thanks (0) Thanks(0)   Quote ricardo Quote  Post ReplyReply Direct Link To This Post Posted: 15 Dec 2024 at 9:57pm
The thing that keeps me from doing that is that i never built an UI for the plugin, its all controlled by xplane data refs .. which is rather not user-friendly.  (i did put together an air manager UI that i use to control it, but that is even more confusing for the average pilot imo) .. 
Back to Top
 Post Reply Post Reply
  Share Topic   

Forum Jump Forum Permissions View Drop Down

Forum Software by Web Wiz Forums® version 12.01
Copyright ©2001-2018 Web Wiz Ltd.

This page was generated in 0.125 seconds.