332 lines
9.7 KiB
C++
332 lines
9.7 KiB
C++
#include "include/main.h"
|
|
|
|
std::mutex mutex;
|
|
std::queue<std::function<void()>> &messageQueue()
|
|
{
|
|
static std::queue<std::function<void()>> _messageQueue;
|
|
return _messageQueue;
|
|
}
|
|
std::thread serverThread;
|
|
std::thread recordingThread;
|
|
std::atomic<bool> wantsExit;
|
|
|
|
std::unique_ptr<germanairlinesva::file::config::Config> configuration;
|
|
std::unique_ptr<germanairlinesva::file::simdata::SimDatabase> database;
|
|
std::unique_ptr<germanairlinesva::websocket::Websocket> 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<germanairlinesva::file::config::Config>();
|
|
toLog("Config loaded");
|
|
|
|
connector = std::make_unique<germanairlinesva::websocket::Websocket>(
|
|
"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<germanairlinesva::file::simdata::SimDatabase>(
|
|
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<std::mutex> 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<std::mutex> 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<std::mutex> lock(mutex);
|
|
|
|
std::memcpy(©, &toSend, sizeof(germanairlinesva::websocket::data));
|
|
}
|
|
|
|
germanairlinesva::file::recording::RecordingEntry currentPath(
|
|
segment,
|
|
static_cast<std::uint16_t>(copy.alt),
|
|
static_cast<std::uint16_t>(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());
|
|
}
|