/* * 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) 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(100); } 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; } 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) { 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_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); if (m_kmlUpdateCount > 0) { m_kmlUpdateCount--; } else { m_pKml->update(m_flightData); m_pKml->export(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; }