#include "include/main.h" std::mutex mutex; std::queue> &messageQueue() { static std::queue> _messageQueue; return _messageQueue; } std::thread serverThread; std::thread recordingThread; std::atomic wantsExit; std::unique_ptr configuration; std::unique_ptr database; std::unique_ptr connector; int xplaneVersion; /* Datarefs */ XPLMDataRef pauseIndicator; XPLMDataRef parkingBrake; XPLMDataRef acftOnGrnd; XPLMDataRef totalFuelKgs; XPLMDataRef trueHeading; XPLMDataRef acftAlt; XPLMDataRef acftGS; XPLMDataRef acftIAS; XPLMDataRef acftVS; XPLMDataRef acftLatitude; XPLMDataRef acftLongitude; XPLMDataRef fuelFlow; XPLMDataRef maxSpeed; XPLMDataRef uptime; XPLMDataRef magHeading; XPLMDataRef timeZulu; XPLMDataRef payloadKgs; XPLMDataRef totalWeightKgs; XPLMDataRef localX; XPLMDataRef localY; XPLMDataRef localZ; XPLMDataRef elevation; XPLMDataRef pitch; XPLMDataRef roll; XPLMDataRef quaternion; struct germanairlinesva::websocket::data toSend; germanairlinesva::file::recording::Recording p; /* * Callbacks */ PLUGIN_API int XPluginStart(char *outName, char *outSig, char *outDesc) { XPLMEnableFeature("XPLM_USE_NATIVE_PATHS", 1); XPLMGetVersions(&xplaneVersion, NULL, NULL); toLog("Plugin using X-Plane Version " + std::to_string(xplaneVersion)); wantsExit.store(false); /* First we must fill in the passed-in buffers to describe our * plugin to the plugin-system. */ strcpy(outName, "GAConnector"); strcpy(outSig, "de.german-airlines.GAConnector"); strcpy(outDesc, "GAConnector"); /* Flight Loop */ XPLMRegisterFlightLoopCallback(flightLoop, -1, nullptr); /* Setup DataRefs */ pauseIndicator = XPLMFindDataRef( "sim/time/sim_speed"); // INT 0=paused, doubles as setting pause(1) parkingBrake = XPLMFindDataRef("sim/flightmodel/controls/parkbrake"); // FLOAT 1=max acftOnGrnd = XPLMFindDataRef("sim/flightmodel/failures/onground_any"); // INT 1=true totalFuelKgs = XPLMFindDataRef("sim/flightmodel/weight/m_fuel_total"); // FLOAT trueHeading = XPLMFindDataRef( "sim/flightmodel/position/true_psi"); // FLOAT degrees north acftAlt = XPLMFindDataRef("sim/flightmodel/position/elevation"); // DOUBLE meters acftGS = XPLMFindDataRef( "sim/flightmodel/position/groundspeed"); // FLOAT meters/second acftIAS = XPLMFindDataRef( "sim/flightmodel/position/indicated_airspeed"); // FLOAT kias acftVS = XPLMFindDataRef( "sim/flightmodel/position/vh_ind_fpm"); // FLOAT feet/minute acftLatitude = XPLMFindDataRef("sim/flightmodel/position/latitude"); // DOUBLE degrees acftLongitude = XPLMFindDataRef("sim/flightmodel/position/longitude"); // DOUBLE degrees fuelFlow = XPLMFindDataRef("sim/flightmodel/engine/ENGN_FF_"); // FLOAT[8] kg/second maxSpeed = XPLMFindDataRef("sim/aircraft/view/acf_Vne"); // FLOAT kias uptime = XPLMFindDataRef("sim/time/total_running_time_sec"); // FLOAT seconds magHeading = XPLMFindDataRef( "sim/flightmodel/position/mag_psi"); // FLOAT degrees north timeZulu = XPLMFindDataRef("sim/time/zulu_time_sec"); // FLOAT seconds since midnight payloadKgs = XPLMFindDataRef("sim/flightmodel/weight/m_fixed"); // FLOAT totalWeightKgs = XPLMFindDataRef("sim/flightmodel/weight/m_total"); // FLOAT localX = XPLMFindDataRef("sim/flightmodel/position/local_x"); // DOUBLE localY = XPLMFindDataRef("sim/flightmodel/position/local_y"); // DOUBLE localZ = XPLMFindDataRef("sim/flightmodel/position/local_z"); // DOUBLE elevation = XPLMFindDataRef("sim/flightmodel/position/elevation"); // DOUBLE pitch = XPLMFindDataRef("sim/flightmodel/position/theta"); // FLOAT roll = XPLMFindDataRef("sim/flightmodel/position/phi"); // FLOAT quaternion = XPLMFindDataRef("sim/flightmodel/position/q"); // FLOAT[4] configuration = std::make_unique(); toLog("Config loaded"); connector = std::make_unique( "wss://ws.hofmannnet.myhome-server.de:8000", configuration->getUser(), toLog); toLog("WebSocket started"); char hash[2 * MD5LEN + 1] = ""; if (germanairlinesva::util::generateMD5(XPLANE_CUSTOM_SCENERY, hash, toLog) == 0) { database = std::make_unique( xplaneVersion, hash, configuration, toLog); } toLog("Readback test of sim database using EDDF"); auto ap = (*database)["EDDF"]; for (const auto &it : ap.first) { toLog(" " + it.to_string()); } for (const auto &it : ap.second) { toLog(" " + it.to_string()); } toLog("Readback test of sim database using XXXX"); auto ap2 = (*database)["XXXX"]; ap2.first.size() == 0 ? toLog(" SUCCESS") : toLog(" ERROR"); // Thread for sending data to websocket serverThread = std::thread(&serverWorker); recordingThread = std::thread(&recordingWorker); toLog("Workers started"); toLog("Logbook Test"); germanairlinesva::file::logbook::Logbook logbook; logbook.addEntry("08.09.2022", "F", "1000", "L049", "D-ALFA", "John F. Kennedy International Aiport / EDDF", "A1", "14L", "Gander International Airport / CYQX", "10", "03", "10:00", "10:20", "13:20", "13:30", 210.5, 20.1, 5012.4156, 8.87, 5041.3856, 7.1, 971.14, 2.41, 980.65, -165.23, 1, 1.2012, "2022-09-08_VGA1000", 5.5, 1); logbook.toFile(); return 1; } PLUGIN_API void XPluginStop(void) { /* Flight Loop */ XPLMUnregisterFlightLoopCallback(flightLoop, nullptr); /* End threads */ wantsExit = true; serverThread.join(); recordingThread.join(); delete connector.release(); delete database.release(); delete configuration.release(); p.toFile("flight.rec"); toLog("Plugin stopped"); } PLUGIN_API void XPluginDisable(void) {} PLUGIN_API int XPluginEnable(void) { return 1; } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" PLUGIN_API void XPluginReceiveMessage(XPLMPluginID inFromWho, long inMessage, void *inParam) { } #pragma clang diagnostic pop #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" float flightLoop(float elapsedMe, float elapsedSim, int counter, void *refcon) { const std::lock_guard lock(mutex); std::memset(&toSend, 0, sizeof(germanairlinesva::websocket::data)); toSend.pause = XPLMGetDatai(pauseIndicator); toSend.pBrake = XPLMGetDataf(parkingBrake); toSend.onGrnd = XPLMGetDatai(acftOnGrnd); toSend.totFuelKg = XPLMGetDataf(totalFuelKgs); toSend.truHdg = XPLMGetDataf(trueHeading); toSend.alt = XPLMGetDatad(acftAlt); toSend.gs = XPLMGetDataf(acftGS); toSend.ias = XPLMGetDataf(acftIAS); toSend.vs = XPLMGetDataf(acftVS); toSend.lat = XPLMGetDatad(acftLatitude); toSend.lon = XPLMGetDatad(acftLongitude); XPLMGetDatavf(fuelFlow, toSend.ff, 0, 8); toSend.maxSpd = XPLMGetDataf(maxSpeed); char *name = (char *)calloc(256, sizeof(char)); XPLMGetNthAircraftModel(0, name, toSend.path); free(name); toSend.uptime = XPLMGetDataf(uptime); toSend.magHeading = XPLMGetDataf(magHeading); toSend.payloadKg = XPLMGetDataf(payloadKgs); toSend.totalWeightKg = XPLMGetDataf(totalWeightKgs); if (!messageQueue().empty()) { auto op = std::move(messageQueue().front()); messageQueue().pop(); op(); } return -1; } #pragma clang diagnostic pop void serverWorker() { germanairlinesva::util::setThreadName("GAServerWorker"); while (!wantsExit) { struct germanairlinesva::websocket::data copy; { const std::lock_guard lock(mutex); std::memcpy(©, &toSend, sizeof(germanairlinesva::websocket::data)); } connector->sendData(copy); std::this_thread::sleep_for(std::chrono::milliseconds(250)); } toLog("Server thread stopped"); } void recordingWorker() { germanairlinesva::util::setThreadName("GARecordingWorker"); germanairlinesva::file::recording::RecordingEntry lastPath; std::uint32_t segment = 0; auto ap = (*database)["EDDF"]; auto rwys = ap.second; while (!wantsExit) { germanairlinesva::websocket::data copy; { const std::lock_guard lock(mutex); std::memcpy(©, &toSend, sizeof(germanairlinesva::websocket::data)); } germanairlinesva::file::recording::RecordingEntry currentPath( segment, static_cast(copy.alt), static_cast(copy.gs), {copy.lat, copy.lon}); if (strcmp(copy.path, "") != 0 && copy.pause && lastPath != currentPath) { p.addEntry(currentPath); lastPath = currentPath; for (const auto &it : rwys) { if (it.containsPoint({copy.lat, copy.lon})) { toLog("On Runway: " + it.to_string()); } } } segment++; std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } toLog("Recording thread stopped"); } void toLog(const std::string &message) { std::time_t utc = std::time(nullptr); std::tm *time = std::gmtime(&utc); std::stringstream msg; msg << std::put_time(time, "%Y-%m-%d %H:%M:%S UTC ") << "German Airlines VA: " << message << std::endl; XPLMDebugString(msg.str().c_str()); }