- added heading to description git-svn-id: http://moon:8086/svn/software/trunk/projects/FsTrack@176 b431acfa-c32f-4a4a-93f1-934dc6c82436
346 lines
9.7 KiB
C++
346 lines
9.7 KiB
C++
/*
|
|
* File: FsLink.cpp
|
|
* Author: jens
|
|
*
|
|
* Created on 9. Januar 2015, 20:14
|
|
*/
|
|
|
|
#include "FsLink.hpp"
|
|
|
|
#define TWO_PWR_16 (65536.0)
|
|
#define TWO_PWR_32 (TWO_PWR_16*TWO_PWR_16)
|
|
#define TIMER_INTEVAL_MS 100
|
|
|
|
const char* FsLink::linkStateString[] = {"Init", "Disconnected", "Connected", "Paused", "Recording"};
|
|
const char* FsLink::flightStateString[] = {"Init", "Suspend", "Ground", "Take off", "Enroute", "Touch down"};
|
|
|
|
FsLink::FsLink(const char *pDocRoot)
|
|
: m_docRoot(pDocRoot)
|
|
, m_pKml(nullptr)
|
|
, m_linkState(ls_init)
|
|
, m_linkStateNext(ls_disconnected)
|
|
, m_flightState(fs_init)
|
|
, m_flightStateNext(fs_suspend)
|
|
, m_kmlUpdateInterval(10)
|
|
, m_kmlUpdateCount(0)
|
|
{
|
|
startTimer(TIMER_INTEVAL_MS);
|
|
}
|
|
|
|
FsLink::FsLink(const FsLink& orig)
|
|
{
|
|
(void)orig;
|
|
}
|
|
|
|
FsLink::~FsLink()
|
|
{
|
|
}
|
|
|
|
void FsLink::addListener(IFsLinkListener *pListener)
|
|
{
|
|
m_listeners.add(pListener);
|
|
}
|
|
|
|
void FsLink::setKml(IKml *pKml)
|
|
{
|
|
m_pKml = pKml;
|
|
}
|
|
|
|
void FsLink::setUpdateInterval(double seconds)
|
|
{
|
|
m_kmlUpdateInterval = (int)(1000*seconds/TIMER_INTEVAL_MS + 0.5);
|
|
}
|
|
|
|
bool FsLink::open()
|
|
{
|
|
unsigned long result;
|
|
static char chOurKey[] = "CJM4KBNN1RLQ"; // As obtained from Pete Dowson
|
|
|
|
memset(m_idStr, 0, sizeof(m_idStr));
|
|
|
|
if(FSUIPC_Open(SIM_ANY, &result))
|
|
{
|
|
// Okay, we're linked, and already the FSUIPC_Open has had an initial
|
|
// exchange with FSUIPC to get its version number and to differentiate
|
|
// between FS's.
|
|
|
|
// Now to auto-Register with FSUIPC, to save the user of an Unregistered FSUIPC
|
|
// having to Register UIPCHello for us:
|
|
|
|
if (FSUIPC_Write(0x8001, 12, chOurKey, &result))
|
|
FSUIPC_Process(&result); // Process the request(s)
|
|
|
|
// I've not checked the reslut of the above -- if it didn't register us,
|
|
// and FSUIPC isn't fully user-Registered, the next request will not
|
|
// return the FS lock time
|
|
|
|
FSUIPC_Read(0x24, sizeof(m_idStr), m_idStr, &result);
|
|
FSUIPC_Process(&result);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void FsLink::close()
|
|
{
|
|
FSUIPC_Close(); // Closing when it wasn't open is okay, so this is safe here
|
|
}
|
|
|
|
int FsLink::gatherData()
|
|
{
|
|
DWORD result;
|
|
unsigned lat_lo, lon_lo, alt_lo;
|
|
char lat[8], lon[8], alt[8], FSRdy2Fly, FSDialog;
|
|
int lat_hi, lon_hi, alt_hi, radio_alt, bank, pitch, hdg_true, gs, tas, ias, bpa, vs, groundLevel, replay_active;
|
|
short mag_var, parking_brake, paused, framerate, plane_on_ground;
|
|
|
|
FSUIPC_Read(0x600C, sizeof(m_flightData.timeZulu), &m_flightData.timeZulu, &result);
|
|
FSUIPC_Read(0x20, sizeof(groundLevel), &groundLevel, &result);
|
|
FSUIPC_Read(0x560, sizeof(lat), lat, &result);
|
|
FSUIPC_Read(0x568, sizeof(lon), lon, &result);
|
|
FSUIPC_Read(0x31E4, sizeof(radio_alt), &radio_alt, &result);
|
|
FSUIPC_Read(0x570, sizeof(alt), alt, &result);
|
|
FSUIPC_Read(0x578, sizeof(pitch), &pitch, &result);
|
|
FSUIPC_Read(0x57C, sizeof(bank), &bank, &result);
|
|
FSUIPC_Read(0x580, sizeof(hdg_true), &hdg_true, &result);
|
|
FSUIPC_Read(0x264, sizeof(paused), &paused, &result);
|
|
FSUIPC_Read(0x274, sizeof(framerate), &framerate, &result);
|
|
FSUIPC_Read(0x2A0, sizeof(mag_var), &mag_var, &result);
|
|
FSUIPC_Read(0x2B4, sizeof(gs), &gs, &result);
|
|
FSUIPC_Read(0x2B8, sizeof(tas), &tas, &result);
|
|
FSUIPC_Read(0x2BC, sizeof(ias), &ias, &result);
|
|
FSUIPC_Read(0x2C4, sizeof(bpa), &bpa, &result);
|
|
FSUIPC_Read(0x2C8, sizeof(vs), &vs, &result);
|
|
FSUIPC_Read(0x3364, sizeof(FSRdy2Fly), &FSRdy2Fly, &result);
|
|
FSUIPC_Read(0x3365, sizeof(FSDialog), &FSDialog, &result);
|
|
FSUIPC_Read(0x3D00, sizeof(m_flightData.aircraftTitle), m_flightData.aircraftTitle, &result);
|
|
FSUIPC_Read(0x3E00, sizeof(m_fsInstallPath), m_fsInstallPath, &result);
|
|
FSUIPC_Read(0x1F96, sizeof(m_flightData.tcasStr), m_flightData.tcasStr, &result);
|
|
FSUIPC_Read(0xF096, sizeof(m_flightData.tcasStr2), m_flightData.tcasStr2, &result);
|
|
FSUIPC_Read(0x3F04, sizeof(m_flightData.flightname), m_flightData.flightname, &result);
|
|
FSUIPC_Read(0x3130, sizeof(m_flightData.atcFlightNumStr), m_flightData.atcFlightNumStr, &result);
|
|
FSUIPC_Read(0x313C, sizeof(m_flightData.atcFlightIDStr), m_flightData.atcFlightIDStr, &result);
|
|
FSUIPC_Read(0x3148, sizeof(m_flightData.atcAirlineStr), m_flightData.atcAirlineStr, &result);
|
|
FSUIPC_Read(0x3160, sizeof(m_flightData.atcAircraftTypeStr), m_flightData.atcAircraftTypeStr, &result);
|
|
FSUIPC_Read(0x366, sizeof(plane_on_ground), &plane_on_ground, &result);
|
|
FSUIPC_Read(0xBC8, sizeof(parking_brake), &parking_brake, &result);
|
|
FSUIPC_Read(0x628, sizeof(replay_active), &replay_active, &result);
|
|
FSUIPC_Process(&result);
|
|
|
|
if (result != FSUIPC_ERR_OK)
|
|
{
|
|
return -(int)result;
|
|
}
|
|
|
|
memcpy(&lat_hi, &lat[4], sizeof(int));
|
|
memcpy(&lat_lo, &lat[0], sizeof(int));
|
|
m_flightData.lat = 90.0*((double)lat_hi + (double)lat_lo/TWO_PWR_32)/10001750; // degrees
|
|
|
|
memcpy(&lon_hi, &lon[4], sizeof(int));
|
|
memcpy(&lon_lo, &lon[0], sizeof(int));
|
|
m_flightData.lon = 360.0*((double)lon_hi + (double)lon_lo/TWO_PWR_32)/TWO_PWR_32; // degrees
|
|
|
|
memcpy(&alt_hi, &alt[4], sizeof(int));
|
|
memcpy(&alt_lo, &alt[0], sizeof(int));
|
|
m_flightData.gl_meter = groundLevel/256; // meter
|
|
m_flightData.alt_meter = (double)radio_alt/65536 + m_flightData.gl_meter; // meter
|
|
m_flightData.alt_feet = 3.28084*m_flightData.alt_meter;
|
|
|
|
m_flightData.pitch_deg = 360.0*(double)pitch/TWO_PWR_32; // degrees
|
|
m_flightData.bank_deg = 360.0*(double)bank/TWO_PWR_32; // degrees
|
|
m_flightData.hdgTrue_deg = 360.0*(double)hdg_true/TWO_PWR_32; // degrees
|
|
if (m_flightData.hdgTrue_deg < 0.0)
|
|
m_flightData.hdgTrue_deg += 360.0;
|
|
if (m_flightData.hdgTrue_deg > 360.0)
|
|
m_flightData.hdgTrue_deg -= 360.0;
|
|
|
|
m_flightData.magVar_deg = 360.0*(double)mag_var/TWO_PWR_16; // degrees
|
|
m_flightData.hdgMag_deg = m_flightData.hdgTrue_deg - m_flightData.magVar_deg;
|
|
if (m_flightData.hdgMag_deg < 0.0)
|
|
m_flightData.hdgMag_deg += 360.0;
|
|
if (m_flightData.hdgMag_deg > 360.0)
|
|
m_flightData.hdgMag_deg -= 360.0;
|
|
|
|
m_flightData.gs_meterPerSec = (double)gs/TWO_PWR_16; // m/s
|
|
m_flightData.gs_knots = 1.946*m_flightData.gs_meterPerSec; // knots
|
|
m_flightData.tas_knots = (double)tas/128.0; // knots
|
|
m_flightData.ias_knots = (double)ias/128.0; // knots
|
|
m_flightData.bpa_knots = (double)bpa/128.0; // knots
|
|
m_flightData.vs_feetPerMin = 100*(double)vs/128.0; // ft/min
|
|
m_flightData.framerate = TWO_PWR_16/(2*framerate);
|
|
m_flightData.isFsReady = (FSRdy2Fly == 0);
|
|
m_flightData.isFsDialog = (FSDialog != 0);
|
|
m_flightData.isPaused = (paused != 0);
|
|
m_flightData.isReplay = (replay_active != 0);
|
|
m_flightData.isParked = (parking_brake != 0);
|
|
m_flightData.isOnGround = (plane_on_ground != 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void FsLink::timerCallback()
|
|
{
|
|
bool doUpdateState = false;
|
|
bool doUpdateData = false;
|
|
|
|
if (m_linkState == ls_disconnected)
|
|
{
|
|
m_linkStateNext = ls_connected;
|
|
if (!open())
|
|
{
|
|
close();
|
|
m_linkStateNext = ls_disconnected;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (gatherData() < 0)
|
|
{
|
|
close();
|
|
m_linkStateNext = ls_disconnected;
|
|
}
|
|
}
|
|
|
|
switch(m_linkState)
|
|
{
|
|
case ls_connected:
|
|
if (!m_flightData.isFsDialog && m_flightData.isFsReady)
|
|
{
|
|
m_pKml->updateFlightData(m_flightData);
|
|
if (m_pKml)
|
|
{
|
|
m_pKml->create();
|
|
}
|
|
m_linkStateNext = ls_recording;
|
|
}
|
|
break;
|
|
|
|
case ls_recording:
|
|
if (m_flightData.isFsDialog && !m_flightData.isFsReady)
|
|
{
|
|
m_pKml->destroy();
|
|
m_linkStateNext = ls_connected;
|
|
break;
|
|
}
|
|
if (m_flightData.isPaused || m_flightData.isReplay)
|
|
{
|
|
m_linkStateNext = ls_paused;
|
|
break;
|
|
}
|
|
doUpdateData = true;
|
|
break;
|
|
|
|
case ls_paused:
|
|
if (m_flightData.isFsDialog)
|
|
{
|
|
m_pKml->destroy();
|
|
m_linkStateNext = ls_connected;
|
|
break;
|
|
}
|
|
if (!(m_flightData.isPaused || m_flightData.isReplay))
|
|
{
|
|
m_linkStateNext = ls_recording;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch(m_flightState)
|
|
{
|
|
case fs_suspend:
|
|
if (m_linkState == ls_disconnected)
|
|
break;
|
|
|
|
if (!m_flightData.isFsDialog && !m_flightData.isReplay)
|
|
{
|
|
m_flightStateNext = fs_ground;
|
|
if (!m_flightData.isOnGround)
|
|
{
|
|
m_flightStateNext = fs_enroute;
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case fs_ground:
|
|
if (!m_flightData.isOnGround)
|
|
{
|
|
m_flightStateNext = fs_takeoff;
|
|
}
|
|
break;
|
|
|
|
case fs_takeoff:
|
|
m_flightStateNext = fs_enroute;
|
|
break;
|
|
|
|
case fs_enroute:
|
|
if (m_flightData.isOnGround)
|
|
{
|
|
m_flightStateNext = fs_touchdown;
|
|
}
|
|
break;
|
|
|
|
case fs_touchdown:
|
|
m_flightStateNext = fs_ground;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Override flight states
|
|
if (m_flightData.isFsDialog || m_flightData.isReplay)
|
|
{
|
|
m_flightStateNext = fs_suspend;
|
|
}
|
|
|
|
doUpdateState = m_linkState != m_linkStateNext;
|
|
doUpdateState |= m_flightState != m_flightStateNext;
|
|
|
|
m_linkState = m_linkStateNext;
|
|
m_flightState = m_flightStateNext;
|
|
|
|
if (doUpdateState)
|
|
{
|
|
m_listeners.call(&IFsLinkListener::onStateChanged, *this);
|
|
}
|
|
|
|
if (doUpdateData)
|
|
{
|
|
m_listeners.call(&IFsLinkListener::onDataChanged, *this);
|
|
|
|
m_pKml->updateFlightData(m_flightData);
|
|
if (m_kmlUpdateCount > 0)
|
|
{
|
|
m_kmlUpdateCount--;
|
|
}
|
|
else
|
|
{
|
|
m_pKml->updateTrack();
|
|
m_pKml->exportKml(m_pKml->getPath());
|
|
m_kmlUpdateCount = m_kmlUpdateInterval;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const char* FsLink::getLinkState()
|
|
{
|
|
return linkStateString[m_linkState];
|
|
}
|
|
|
|
const char* FsLink::getFlightState()
|
|
{
|
|
return flightStateString[m_flightState];
|
|
}
|
|
|
|
FlightData FsLink::getFlightData()
|
|
{
|
|
return m_flightData;
|
|
}
|