#include "include/main.h" std::mutex mutex; std::queue> &messageQueue() { static std::queue> _messageQueue; return _messageQueue; } std::thread serverThread; std::atomic wantsExit; 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; /* * 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, "WebSocketTestXPlane"); strcpy(outSig, "de.german-airlines.WebSocketTestXPlane"); strcpy(outDesc, "WebSocketTestXPlane"); /* 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; } // Thread for sending data to web socket serverThread = std::thread(&serverWorker); toLog("WebSocketTestXPlane initialized and ready"); return 1; } PLUGIN_API void XPluginStop(void) { /* Flight Loop */ XPLMUnregisterFlightLoopCallback(flightLoop, nullptr); /* End threads */ wantsExit = true; delete connector; serverThread.join(); } PLUGIN_API void XPluginDisable(void) {} PLUGIN_API int XPluginEnable(void) { return 1; } PLUGIN_API void XPluginReceiveMessage(XPLMPluginID inFromWho, long inMessage, void *inParam) { } 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; } void serverWorker() { 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 toLog(const std::string &message) { std::stringstream msg; msg << "German Airlines VA: " << message << std::endl; XPLMDebugString(msg.str().c_str()); }