This commit is contained in:
Kilian Hofmann 2022-09-11 23:26:28 +02:00
parent 46a0607b55
commit 07487e9e51
17 changed files with 161 additions and 180 deletions

View File

@ -1,5 +1,3 @@
- Reverse engineer FSUIPC .NET onRunway Check - Reverse engineer FSUIPC .NET onRunway Check
- Update OSXCross Docker image to SDK 11 - Update OSXCross Docker image to SDK 11
- Implement ARM64 arch for Plugin - Implement ARM64 arch for Plugin
- Refactor SimDatabase to be a class
- Requires new Airport class

View File

@ -20,11 +20,10 @@ namespace file
std::ifstream in(XPLANE_PLUGIN_DIRECTORY CONFIG); std::ifstream in(XPLANE_PLUGIN_DIRECTORY CONFIG);
std::string line; std::string line;
while (std::getline(in, line)) { while (std::getline(in, line)) {
std::vector<std::string> fields = std::vector<std::string> fields = util::split(line, '=');
germanairlinesva::util::split(line, '=');
if (fields.size() >= 2) { if (fields.size() >= 2) {
germanairlinesva::util::trim(fields[0]); util::trim(fields[0]);
germanairlinesva::util::trim(fields[1]); util::trim(fields[1]);
if (fields[0] == "scenery") { if (fields[0] == "scenery") {
this->scenery = fields[1]; this->scenery = fields[1];
} else if (fields[0] == "user") { } else if (fields[0] == "user") {

View File

@ -7,7 +7,7 @@ namespace file
namespace simdata namespace simdata
{ {
Gate::Gate(std::string designator, Gate::Gate(std::string designator,
struct germanairlinesva::geodata::point center, struct geodata::point center,
std::uint8_t radius) std::uint8_t radius)
{ {
this->designator = designator; this->designator = designator;
@ -22,10 +22,9 @@ namespace file
write<decltype(this->radius)>(out, this->radius); write<decltype(this->radius)>(out, this->radius);
} }
bool Gate::contains(germanairlinesva::geodata::point coordinates) const bool Gate::contains(geodata::point coordinates) const
{ {
return germanairlinesva::geodata::distanceEarthP(this->center, return geodata::distanceEarthP(this->center, coordinates);
coordinates);
} }
} // namespace simdata } // namespace simdata
} // namespace file } // namespace file

View File

@ -26,14 +26,16 @@ namespace file
std::uint32_t time; std::uint32_t time;
std::uint16_t altitude = 0; std::uint16_t altitude = 0;
std::uint16_t groundSpeed = 0; std::uint16_t groundSpeed = 0;
struct germanairlinesva::geodata::point coordinates{NAN, NAN}; struct geodata::point coordinates {
NAN, NAN
};
public: public:
RecordingEntry() = default; RecordingEntry() = default;
RecordingEntry(std::uint32_t time, RecordingEntry(std::uint32_t time,
std::uint16_t altitude, std::uint16_t altitude,
std::uint16_t groundSpeed, std::uint16_t groundSpeed,
struct germanairlinesva::geodata::point coordinates); struct geodata::point coordinates);
void toFile(std::ofstream &out) const; void toFile(std::ofstream &out) const;

View File

@ -34,16 +34,16 @@ namespace file
{ {
private: private:
std::string designator; std::string designator;
struct germanairlinesva::geodata::point center; struct geodata::point center;
std::uint8_t radius; std::uint8_t radius;
public: public:
Gate(std::string designator, Gate(std::string designator,
struct germanairlinesva::geodata::point center, struct geodata::point center,
std::uint8_t radius); std::uint8_t radius);
void toFile(std::ofstream &out) const; void toFile(std::ofstream &out) const;
bool contains(germanairlinesva::geodata::point coordinates) const; bool contains(geodata::point coordinates) const;
inline const std::string to_string() const inline const std::string to_string() const
{ {

View File

@ -34,7 +34,7 @@ namespace file
{ {
private: private:
std::string designator; std::string designator;
struct germanairlinesva::geodata::box bounds; struct geodata::box bounds;
std::uint8_t width; std::uint8_t width;
std::uint16_t length; std::uint16_t length;
std::uint16_t trueHeading; std::uint16_t trueHeading;
@ -50,7 +50,7 @@ namespace file
double width); double width);
// From database // From database
Runway(std::string designator, Runway(std::string designator,
struct germanairlinesva::geodata::box bounds, struct geodata::box bounds,
std::uint8_t width, std::uint8_t width,
std::uint16_t length, std::uint16_t length,
std::uint16_t trueHeading); std::uint16_t trueHeading);

View File

@ -42,10 +42,7 @@ namespace file
class SimDatabase class SimDatabase
{ {
private: private:
std::map< std::map<std::string, std::pair<std::vector<Gate>, std::vector<Runway>>>
std::string,
std::pair<std::vector<germanairlinesva::file::simdata::Gate>,
std::vector<germanairlinesva::file::simdata::Runway>>>
airports; airports;
void fromFile(); void fromFile();
@ -64,11 +61,11 @@ namespace file
const std::vector<Runway>> const std::vector<Runway>>
operator[](std::string key) operator[](std::string key)
{ {
try { auto it = this->airports.find(key);
return this->airports.at(key); if (it != this->airports.end()) {
} catch (std::out_of_range &ex) { return this->airports[key];
return std::pair<const std::vector<Gate>, } else {
const std::vector<Runway>>(); return std::pair<std::vector<Gate>, std::vector<Runway>>();
} }
} }
}; };

View File

@ -20,15 +20,13 @@ namespace file
const std::string defaultFile, const std::string defaultFile,
const std::string sceneryPack, const std::string sceneryPack,
const std::string logFile, const std::string logFile,
std::map<std::string, std::map<std::string, std::pair<std::vector<Gate>, std::vector<Runway>>>
std::pair<std::vector<Gate>, std::vector<Runway>>>
&airports); &airports);
void makeAirport( void makeAirport(
const std::string &kind, const std::string &kind,
std::ifstream &infile, std::ifstream &infile,
std::map<std::string, std::map<std::string, std::pair<std::vector<Gate>, std::vector<Runway>>>
std::pair<std::vector<Gate>, std::vector<Runway>>>
&airports, &airports,
std::ofstream &logfile); std::ofstream &logfile);
void makeGate15(std::vector<Gate> &gates, void makeGate15(std::vector<Gate> &gates,

View File

@ -8,7 +8,7 @@ namespace file
{ {
Logbook::Logbook() Logbook::Logbook()
{ {
if (germanairlinesva::util::fileExists(XPLANE_PLUGIN_DIRECTORY LOGBOOK)) { if (util::fileExists(XPLANE_PLUGIN_DIRECTORY LOGBOOK)) {
this->fromFile(); this->fromFile();
} }
} }

View File

@ -7,11 +7,10 @@ namespace file
{ {
namespace recording namespace recording
{ {
RecordingEntry::RecordingEntry( RecordingEntry::RecordingEntry(std::uint32_t time,
std::uint32_t time, std::uint16_t altitude,
std::uint16_t altitude, std::uint16_t groundSpeed,
std::uint16_t groundSpeed, struct geodata::point coordinates)
struct germanairlinesva::geodata::point coordinates)
{ {
this->time = time; this->time = time;
this->altitude = altitude; this->altitude = altitude;

View File

@ -15,24 +15,23 @@ namespace file
{ {
this->designator = designator; this->designator = designator;
this->width = width; this->width = width;
this->length = germanairlinesva::geodata::distanceEarthD(latitudeStart, this->length = geodata::distanceEarthD(latitudeStart,
longitudeStart, longitudeStart,
latitudeEnd, latitudeEnd,
longitudeEnd); longitudeEnd);
this->trueHeading = (std::uint16_t)std::round( this->trueHeading =
germanairlinesva::geodata::bearingDD(latitudeStart, (std::uint16_t)std::round(geodata::bearingDD(latitudeStart,
longitudeStart, longitudeStart,
latitudeEnd, latitudeEnd,
longitudeEnd)); longitudeEnd));
this->bounds = germanairlinesva::geodata::calculateBoxDD( this->bounds = geodata::calculateBoxDD({latitudeStart, longitudeStart},
{latitudeStart, longitudeStart}, {latitudeEnd, longitudeEnd},
{latitudeEnd, longitudeEnd}, this->trueHeading,
this->trueHeading, this->width);
this->width);
} }
Runway::Runway(std::string designator, Runway::Runway(std::string designator,
germanairlinesva::geodata::box bounds, geodata::box bounds,
std::uint8_t width, std::uint8_t width,
std::uint16_t length, std::uint16_t length,
std::uint16_t trueHeading) std::uint16_t trueHeading)

View File

@ -56,8 +56,7 @@ namespace file
std::uint16_t numGates = read<std::uint16_t>(in); std::uint16_t numGates = read<std::uint16_t>(in);
for (int j = 0; j < numGates; j++) { for (int j = 0; j < numGates; j++) {
std::string designator = readString(in); std::string designator = readString(in);
struct germanairlinesva::geodata::point center = struct geodata::point center = read<struct geodata::point>(in);
read<struct germanairlinesva::geodata::point>(in);
std::uint8_t radius = read<std::uint8_t>(in); std::uint8_t radius = read<std::uint8_t>(in);
this->airports[icao].first.emplace_back(designator, center, radius); this->airports[icao].first.emplace_back(designator, center, radius);
@ -67,8 +66,7 @@ namespace file
for (int j = 0; j < numRunways; j++) { for (int j = 0; j < numRunways; j++) {
std::string designator = readString(in); std::string designator = readString(in);
// Bounds // Bounds
struct germanairlinesva::geodata::box bounds = struct geodata::box bounds = read<struct geodata::box>(in);
read<struct germanairlinesva::geodata::box>(in);
std::uint8_t width = read<std::uint8_t>(in); std::uint8_t width = read<std::uint8_t>(in);
std::uint16_t length = read<std::uint16_t>(in); std::uint16_t length = read<std::uint16_t>(in);
std::uint16_t trueHeading = read<std::uint16_t>(in); std::uint16_t trueHeading = read<std::uint16_t>(in);

View File

@ -39,9 +39,8 @@ namespace file
std::vector<std::string> packs; std::vector<std::string> packs;
while (std::getline(custom, line)) { while (std::getline(custom, line)) {
if ((pos = line.find("SCENERY_PACK")) != std::string::npos) { if ((pos = line.find("SCENERY_PACK")) != std::string::npos) {
std::string path = std::string path = util::rtrim_copy(line.substr(pos + 13)) +
germanairlinesva::util::rtrim_copy(line.substr(pos + 13)) + "Earth nav data/apt.dat";
"Earth nav data/apt.dat";
packs.emplace_back(path); packs.emplace_back(path);
} }
} }
@ -84,11 +83,10 @@ namespace file
int validCount = 0; int validCount = 0;
while (std::getline(infile, line)) { while (std::getline(infile, line)) {
std::vector<std::string> fields = std::vector<std::string> fields = util::split(line, ' ');
germanairlinesva::util::split(line, ' '); fields = util::select_T<std::string>(fields, [](const std::string &s) {
fields = germanairlinesva::util::select_T<std::string>( return s.length() > 0;
fields, });
[](const std::string &s) { return s.length() > 0; });
if (fields.empty()) if (fields.empty())
continue; continue;
@ -155,7 +153,7 @@ namespace file
} }
gateName += fields.back(); gateName += fields.back();
gateName = std::regex_replace(gateName, std::regex{","}, "0"); gateName = std::regex_replace(gateName, std::regex{","}, "0");
struct germanairlinesva::geodata::point pt { struct geodata::point pt {
std::stod(fields[1]), std::stod(fields[2]) std::stod(fields[1]), std::stod(fields[2])
}; };
gates.emplace_back(gateName, pt, 40); gates.emplace_back(gateName, pt, 40);
@ -188,7 +186,7 @@ namespace file
gateName += fields.back(); gateName += fields.back();
gateName = std::regex_replace(gateName, std::regex{","}, "0"); gateName = std::regex_replace(gateName, std::regex{","}, "0");
struct germanairlinesva::geodata::point pt { struct geodata::point pt {
std::stod(fields[1]), std::stod(fields[2]) std::stod(fields[1]), std::stod(fields[2])
}; };
gates.emplace_back(gateName, pt, 40); gates.emplace_back(gateName, pt, 40);

View File

@ -3,8 +3,9 @@
#include <cstdint> #include <cstdint>
namespace germanairlinesva
namespace germanairlinesva_websocket {
namespace websocket
{ {
#pragma pack(push) /* push current alignment to stack */ #pragma pack(push) /* push current alignment to stack */
#pragma pack(1) /* set alignment to 1 byte boundary */ #pragma pack(1) /* set alignment to 1 byte boundary */
@ -44,6 +45,7 @@ namespace germanairlinesva_websocket
}; };
#pragma pack(pop) /* restore original alignment from stack */ #pragma pack(pop) /* restore original alignment from stack */
} // namespace germanairlinesva_websocket } // namespace websocket
} // namespace germanairlinesva
#endif #endif

View File

@ -18,7 +18,9 @@
#include <string> #include <string>
#include <utility> #include <utility>
namespace germanairlinesva_websocket namespace germanairlinesva
{
namespace websocket
{ {
class Websocket class Websocket
{ {
@ -38,6 +40,7 @@ namespace germanairlinesva_websocket
void onClientMessageCallback(const ix::WebSocketMessagePtr &msg); void onClientMessageCallback(const ix::WebSocketMessagePtr &msg);
void sendData(data &d); void sendData(data &d);
}; };
} // namespace germanairlinesva_websocket } // namespace websocket
} // namespace germanairlinesva
#endif #endif

View File

@ -1,113 +1,114 @@
#include "include/websocket.h" #include "include/websocket.h"
namespace germanairlinesva_websocket namespace germanairlinesva
{ {
Websocket::Websocket(std::string host, namespace websocket
std::string user,
std::function<void(const std::string)> toLog)
: host(host), user(user), toLog(std::move(toLog))
{ {
Websocket::Websocket(std::string host,
std::string user,
std::function<void(const std::string)> toLog)
: host(host), user(user), toLog(std::move(toLog))
{
#ifdef IBM #ifdef IBM
// Required on Windows // Required on Windows
ix::initNetSystem(); ix::initNetSystem();
#endif #endif
this->webSocket = new ix::WebSocket(); this->webSocket = new ix::WebSocket();
this->webSocket->enableAutomaticReconnection(); this->webSocket->enableAutomaticReconnection();
this->webSocket->setUrl(host); this->webSocket->setUrl(host);
this->webSocket->setOnMessageCallback( this->webSocket->setOnMessageCallback(
[this](const ix::WebSocketMessagePtr &msg) { [this](const ix::WebSocketMessagePtr &msg) {
this->onClientMessageCallback(msg); this->onClientMessageCallback(msg);
}); });
this->webSocket->start(); this->webSocket->start();
} }
Websocket::~Websocket() Websocket::~Websocket()
{ {
this->webSocket->stop(); this->webSocket->stop();
this->toLog("WebSocket stopped"); this->toLog("WebSocket stopped");
#ifdef IBM #ifdef IBM
// Required on Windows // Required on Windows
ix::uninitNetSystem(); ix::uninitNetSystem();
#endif #endif
} }
void Websocket::onClientMessageCallback(const ix::WebSocketMessagePtr &msg) void Websocket::onClientMessageCallback(const ix::WebSocketMessagePtr &msg)
{ {
if (msg->type == ix::WebSocketMessageType::Open) { if (msg->type == ix::WebSocketMessageType::Open) {
std::stringstream debug_msg;
debug_msg << std::endl << "New connection" << std::endl;
debug_msg << "Uri: " << msg->openInfo.uri << std::endl;
debug_msg << "Headers:" << std::endl;
for (const auto &it : msg->openInfo.headers) {
debug_msg << it.first << ": " << it.second << std::endl;
}
this->toLog(debug_msg.str());
this->webSocket->send("MASTER:" + user);
this->toLog("Connecting as " + user);
} else if (msg->type == ix::WebSocketMessageType::Close) {
if (msg->closeInfo.reason.compare("DUPLICATE") == 0) {
this->webSocket->disableAutomaticReconnection();
this->toLog("Disconnected due to beeing a duplicate simualtor");
} else {
std::stringstream debug_msg; std::stringstream debug_msg;
debug_msg << std::endl << "Connection closed" << std::endl; debug_msg << std::endl << "New connection" << std::endl;
debug_msg << "Code: " << msg->closeInfo.code << std::endl; debug_msg << "Uri: " << msg->openInfo.uri << std::endl;
debug_msg << "Reason: " << msg->closeInfo.reason << std::endl; debug_msg << "Headers:" << std::endl;
debug_msg << "Remote: " << msg->closeInfo.remote << std::endl; for (const auto &it : msg->openInfo.headers) {
debug_msg << it.first << ": " << it.second << std::endl;
}
this->toLog(debug_msg.str()); this->toLog(debug_msg.str());
}
} else if (msg->type == ix::WebSocketMessageType::Error) {
std::stringstream debug_msg;
debug_msg << std::endl << "Connection error" << std::endl; this->webSocket->send("MASTER:" + user);
debug_msg << "Decompression: " << msg->errorInfo.decompressionError this->toLog("Connecting as " + user);
<< std::endl; } else if (msg->type == ix::WebSocketMessageType::Close) {
debug_msg << "HTTP status: " << msg->errorInfo.http_status << std::endl; if (msg->closeInfo.reason.compare("DUPLICATE") == 0) {
debug_msg << "Reason: " << msg->errorInfo.reason << std::endl; this->webSocket->disableAutomaticReconnection();
debug_msg << "Retries: " << msg->errorInfo.retries << std::endl;
debug_msg << "Wait time: " << msg->errorInfo.wait_time << std::endl;
this->toLog(debug_msg.str()); this->toLog("Disconnected due to beeing a duplicate simualtor");
} else if (msg->type == ix::WebSocketMessageType::Message) { } else {
if (!msg->str.empty()) { std::stringstream debug_msg;
this->toLog(msg->str);
}
}
}
void Websocket::sendData(data &d) debug_msg << std::endl << "Connection closed" << std::endl;
{ debug_msg << "Code: " << msg->closeInfo.code << std::endl;
if (strcmp(d.path, this->lastPath) != 0) { debug_msg << "Reason: " << msg->closeInfo.reason << std::endl;
strcpy(this->lastPath, d.path); debug_msg << "Remote: " << msg->closeInfo.remote << std::endl;
if (germanairlinesva::util::generateMD5(d.path,
this->lastHash, this->toLog(debug_msg.str());
this->toLog)) { }
strcpy(this->lastHash, "NOT SET"); } else if (msg->type == ix::WebSocketMessageType::Error) {
std::stringstream debug_msg;
debug_msg << std::endl << "Connection error" << std::endl;
debug_msg << "Decompression: " << msg->errorInfo.decompressionError
<< std::endl;
debug_msg << "HTTP status: " << msg->errorInfo.http_status << std::endl;
debug_msg << "Reason: " << msg->errorInfo.reason << std::endl;
debug_msg << "Retries: " << msg->errorInfo.retries << std::endl;
debug_msg << "Wait time: " << msg->errorInfo.wait_time << std::endl;
this->toLog(debug_msg.str());
} else if (msg->type == ix::WebSocketMessageType::Message) {
if (!msg->str.empty()) {
this->toLog(msg->str);
}
} }
} }
nlohmann::json json = { void Websocket::sendData(data &d)
{"altitude", d.alt}, {
{"vs", d.vs}, if (strcmp(d.path, this->lastPath) != 0) {
{"ias", d.ias}, strcpy(this->lastPath, d.path);
{"magHdg", d.magHeading}, if (util::generateMD5(d.path, this->lastHash, this->toLog)) {
{"truHdg", d.truHdg}, strcpy(this->lastHash, "NOT SET");
{"totFuel", d.totFuelKg}, }
{"fuelFlow", d.ff}, }
{"hash", this->lastHash},
};
if (this->webSocket != nullptr) { nlohmann::json json = {
std::ostringstream msg; {"altitude", d.alt},
msg << "SEND:" << user << ":" << json.dump(); {"vs", d.vs},
this->webSocket->send(msg.str(), false); {"ias", d.ias},
{"magHdg", d.magHeading},
{"truHdg", d.truHdg},
{"totFuel", d.totFuelKg},
{"fuelFlow", d.ff},
{"hash", this->lastHash},
};
if (this->webSocket != nullptr) {
std::ostringstream msg;
msg << "SEND:" << user << ":" << json.dump();
this->webSocket->send(msg.str(), false);
}
} }
} } // namespace websocket
} // namespace germanairlinesva_websocket } // namespace germanairlinesva

View File

@ -12,7 +12,7 @@ std::atomic<bool> wantsExit;
std::unique_ptr<germanairlinesva::file::config::Config> configuration; std::unique_ptr<germanairlinesva::file::config::Config> configuration;
std::unique_ptr<germanairlinesva::file::simdata::SimDatabase> database; std::unique_ptr<germanairlinesva::file::simdata::SimDatabase> database;
std::unique_ptr<germanairlinesva_websocket::Websocket> connector; std::unique_ptr<germanairlinesva::websocket::Websocket> connector;
int xplaneVersion; int xplaneVersion;
/* Datarefs */ /* Datarefs */
@ -43,7 +43,7 @@ XPLMDataRef pitch;
XPLMDataRef roll; XPLMDataRef roll;
XPLMDataRef quaternion; XPLMDataRef quaternion;
struct germanairlinesva_websocket::data toSend; struct germanairlinesva::websocket::data toSend;
germanairlinesva::file::recording::Recording p; germanairlinesva::file::recording::Recording p;
/* /*
@ -114,7 +114,7 @@ PLUGIN_API int XPluginStart(char *outName, char *outSig, char *outDesc)
configuration = std::make_unique<germanairlinesva::file::config::Config>(); configuration = std::make_unique<germanairlinesva::file::config::Config>();
toLog("Config loaded"); toLog("Config loaded");
connector = std::make_unique<germanairlinesva_websocket::Websocket>( connector = std::make_unique<germanairlinesva::websocket::Websocket>(
"wss://ws.hofmannnet.myhome-server.de:8000", "wss://ws.hofmannnet.myhome-server.de:8000",
configuration->getUser(), configuration->getUser(),
toLog); toLog);
@ -128,18 +128,6 @@ PLUGIN_API int XPluginStart(char *outName, char *outSig, char *outDesc)
hash, hash,
configuration, configuration,
toLog); 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 // Thread for sending data to websocket
@ -219,7 +207,7 @@ float flightLoop(float elapsedMe, float elapsedSim, int counter, void *refcon)
{ {
const std::lock_guard<std::mutex> lock(mutex); const std::lock_guard<std::mutex> lock(mutex);
std::memset(&toSend, 0, sizeof(germanairlinesva_websocket::data)); std::memset(&toSend, 0, sizeof(germanairlinesva::websocket::data));
toSend.pause = XPLMGetDatai(pauseIndicator); toSend.pause = XPLMGetDatai(pauseIndicator);
toSend.pBrake = XPLMGetDataf(parkingBrake); toSend.pBrake = XPLMGetDataf(parkingBrake);
@ -260,11 +248,11 @@ void serverWorker()
germanairlinesva::util::setThreadName("GAServerWorker"); germanairlinesva::util::setThreadName("GAServerWorker");
while (!wantsExit) { while (!wantsExit) {
struct germanairlinesva_websocket::data copy; struct germanairlinesva::websocket::data copy;
{ {
const std::lock_guard<std::mutex> lock(mutex); const std::lock_guard<std::mutex> lock(mutex);
std::memcpy(&copy, &toSend, sizeof(germanairlinesva_websocket::data)); std::memcpy(&copy, &toSend, sizeof(germanairlinesva::websocket::data));
} }
connector->sendData(copy); connector->sendData(copy);
@ -283,11 +271,11 @@ void recordingWorker()
std::uint32_t segment = 0; std::uint32_t segment = 0;
while (!wantsExit) { while (!wantsExit) {
germanairlinesva_websocket::data copy; germanairlinesva::websocket::data copy;
{ {
const std::lock_guard<std::mutex> lock(mutex); const std::lock_guard<std::mutex> lock(mutex);
std::memcpy(&copy, &toSend, sizeof(germanairlinesva_websocket::data)); std::memcpy(&copy, &toSend, sizeof(germanairlinesva::websocket::data));
} }
germanairlinesva::file::recording::RecordingEntry currentPath( germanairlinesva::file::recording::RecordingEntry currentPath(