#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::map configuration; Websocket *connector; /* 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; data toSend; Path p; /* * Callbacks */ PLUGIN_API int XPluginStart(char *outName, char *outSig, char *outDesc) { XPLMEnableFeature("XPLM_USE_NATIVE_PATHS", 1); 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] // Initialize connector try { connector = new Websocket(toLog); } catch (const std::invalid_argument &e) { toLog(e.what()); return 0; } toLog("WebSocket started"); configuration = config::readConfig("Resources/plugins/GAConnector/config.cfg"); toLog("Config loaded"); char hash[2 * MD5LEN + 1] = ""; if (util::generateMD5("Custom Scenery/scenery_packs.ini", hash, toLog) == 0) { std::map, std::vector>> airports; if (strcmp(configuration["scenery"].c_str(), hash) != 0) { scan("Resources/default scenery/default apt dat/Earth nav " "data/apt.dat", "Custom Scenery/scenery_packs.ini", "Resources/plugins/GAConnector/log.txt", airports); simulatorDatabase::toFile(airports, "Resources/plugins/GAConnector/sim.bin"); configuration["scenery"] = hash; config::writeConfig(configuration, "Resources/plugins/GAConnector/config.cfg"); toLog("Sim Database updated"); } else { airports = simulatorDatabase::fromFile( "Resources/plugins/GAConnector/sim.bin"); toLog("Sim Database loaded"); } } // Thread for sending data to web socket serverThread = std::thread(&serverWorker); recordingThread = std::thread(&recordingWorker); toLog("Workers started"); return 1; } PLUGIN_API void XPluginStop(void) { /* Flight Loop */ XPLMUnregisterFlightLoopCallback(flightLoop, nullptr); /* End threads */ wantsExit = true; delete connector; serverThread.join(); recordingThread.join(); std::ofstream out("Resources/plugins/GAConnector/flight.rec"); out.write(reinterpret_cast(p.getBinaryData()), (std::streamsize)p.getBinaryLength()); out.close(); } 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); memset(&toSend, 0, sizeof(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() { util::setThreadName("GAServerWorker"); while (!wantsExit) { data copy; { const std::lock_guard lock(mutex); memcpy(©, &toSend, sizeof(data)); } connector->sendData(copy); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } } void recordingWorker() { util::setThreadName("GARecordingWorker"); PathSegment lastPath; while (!wantsExit) { data copy; { const std::lock_guard lock(mutex); memcpy(©, &toSend, sizeof(data)); } PathSegment currentPath(static_cast(copy.alt), static_cast(copy.gs), copy.lat, copy.lon); if (strcmp(copy.path, "") != 0 && copy.pause && lastPath != currentPath) { p.addSegment(currentPath); lastPath = currentPath; } std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } } void toLog(const std::string &message) { std::stringstream msg; msg << "German Airlines VA: " << message << std::endl; XPLMDebugString(msg.str().c_str()); }