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
- Update OSXCross Docker image to SDK 11
- 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::string line;
while (std::getline(in, line)) {
std::vector<std::string> fields =
germanairlinesva::util::split(line, '=');
std::vector<std::string> fields = util::split(line, '=');
if (fields.size() >= 2) {
germanairlinesva::util::trim(fields[0]);
germanairlinesva::util::trim(fields[1]);
util::trim(fields[0]);
util::trim(fields[1]);
if (fields[0] == "scenery") {
this->scenery = fields[1];
} else if (fields[0] == "user") {

View File

@ -7,7 +7,7 @@ namespace file
namespace simdata
{
Gate::Gate(std::string designator,
struct germanairlinesva::geodata::point center,
struct geodata::point center,
std::uint8_t radius)
{
this->designator = designator;
@ -22,10 +22,9 @@ namespace file
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,
coordinates);
return geodata::distanceEarthP(this->center, coordinates);
}
} // namespace simdata
} // namespace file

View File

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

View File

@ -34,16 +34,16 @@ namespace file
{
private:
std::string designator;
struct germanairlinesva::geodata::point center;
struct geodata::point center;
std::uint8_t radius;
public:
Gate(std::string designator,
struct germanairlinesva::geodata::point center,
struct geodata::point center,
std::uint8_t radius);
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
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -56,8 +56,7 @@ namespace file
std::uint16_t numGates = read<std::uint16_t>(in);
for (int j = 0; j < numGates; j++) {
std::string designator = readString(in);
struct germanairlinesva::geodata::point center =
read<struct germanairlinesva::geodata::point>(in);
struct geodata::point center = read<struct geodata::point>(in);
std::uint8_t radius = read<std::uint8_t>(in);
this->airports[icao].first.emplace_back(designator, center, radius);
@ -67,8 +66,7 @@ namespace file
for (int j = 0; j < numRunways; j++) {
std::string designator = readString(in);
// Bounds
struct germanairlinesva::geodata::box bounds =
read<struct germanairlinesva::geodata::box>(in);
struct geodata::box bounds = read<struct geodata::box>(in);
std::uint8_t width = read<std::uint8_t>(in);
std::uint16_t length = 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;
while (std::getline(custom, line)) {
if ((pos = line.find("SCENERY_PACK")) != std::string::npos) {
std::string path =
germanairlinesva::util::rtrim_copy(line.substr(pos + 13)) +
"Earth nav data/apt.dat";
std::string path = util::rtrim_copy(line.substr(pos + 13)) +
"Earth nav data/apt.dat";
packs.emplace_back(path);
}
}
@ -84,11 +83,10 @@ namespace file
int validCount = 0;
while (std::getline(infile, line)) {
std::vector<std::string> fields =
germanairlinesva::util::split(line, ' ');
fields = germanairlinesva::util::select_T<std::string>(
fields,
[](const std::string &s) { return s.length() > 0; });
std::vector<std::string> fields = util::split(line, ' ');
fields = util::select_T<std::string>(fields, [](const std::string &s) {
return s.length() > 0;
});
if (fields.empty())
continue;
@ -155,7 +153,7 @@ namespace file
}
gateName += fields.back();
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])
};
gates.emplace_back(gateName, pt, 40);
@ -188,7 +186,7 @@ namespace file
gateName += fields.back();
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])
};
gates.emplace_back(gateName, pt, 40);

View File

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

View File

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

View File

@ -1,113 +1,114 @@
#include "include/websocket.h"
namespace germanairlinesva_websocket
namespace germanairlinesva
{
Websocket::Websocket(std::string host,
std::string user,
std::function<void(const std::string)> toLog)
: host(host), user(user), toLog(std::move(toLog))
namespace websocket
{
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
// Required on Windows
ix::initNetSystem();
// Required on Windows
ix::initNetSystem();
#endif
this->webSocket = new ix::WebSocket();
this->webSocket->enableAutomaticReconnection();
this->webSocket->setUrl(host);
this->webSocket->setOnMessageCallback(
[this](const ix::WebSocketMessagePtr &msg) {
this->onClientMessageCallback(msg);
});
this->webSocket->start();
}
this->webSocket = new ix::WebSocket();
this->webSocket->enableAutomaticReconnection();
this->webSocket->setUrl(host);
this->webSocket->setOnMessageCallback(
[this](const ix::WebSocketMessagePtr &msg) {
this->onClientMessageCallback(msg);
});
this->webSocket->start();
}
Websocket::~Websocket()
{
this->webSocket->stop();
this->toLog("WebSocket stopped");
Websocket::~Websocket()
{
this->webSocket->stop();
this->toLog("WebSocket stopped");
#ifdef IBM
// Required on Windows
ix::uninitNetSystem();
// Required on Windows
ix::uninitNetSystem();
#endif
}
}
void Websocket::onClientMessageCallback(const ix::WebSocketMessagePtr &msg)
{
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 {
void Websocket::onClientMessageCallback(const ix::WebSocketMessagePtr &msg)
{
if (msg->type == ix::WebSocketMessageType::Open) {
std::stringstream debug_msg;
debug_msg << std::endl << "Connection closed" << std::endl;
debug_msg << "Code: " << msg->closeInfo.code << std::endl;
debug_msg << "Reason: " << msg->closeInfo.reason << std::endl;
debug_msg << "Remote: " << msg->closeInfo.remote << std::endl;
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());
}
} 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->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(debug_msg.str());
} else if (msg->type == ix::WebSocketMessageType::Message) {
if (!msg->str.empty()) {
this->toLog(msg->str);
}
}
}
this->toLog("Disconnected due to beeing a duplicate simualtor");
} else {
std::stringstream debug_msg;
void Websocket::sendData(data &d)
{
if (strcmp(d.path, this->lastPath) != 0) {
strcpy(this->lastPath, d.path);
if (germanairlinesva::util::generateMD5(d.path,
this->lastHash,
this->toLog)) {
strcpy(this->lastHash, "NOT SET");
debug_msg << std::endl << "Connection closed" << std::endl;
debug_msg << "Code: " << msg->closeInfo.code << std::endl;
debug_msg << "Reason: " << msg->closeInfo.reason << std::endl;
debug_msg << "Remote: " << msg->closeInfo.remote << std::endl;
this->toLog(debug_msg.str());
}
} 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 = {
{"altitude", d.alt},
{"vs", d.vs},
{"ias", d.ias},
{"magHdg", d.magHeading},
{"truHdg", d.truHdg},
{"totFuel", d.totFuelKg},
{"fuelFlow", d.ff},
{"hash", this->lastHash},
};
void Websocket::sendData(data &d)
{
if (strcmp(d.path, this->lastPath) != 0) {
strcpy(this->lastPath, d.path);
if (util::generateMD5(d.path, this->lastHash, this->toLog)) {
strcpy(this->lastHash, "NOT SET");
}
}
if (this->webSocket != nullptr) {
std::ostringstream msg;
msg << "SEND:" << user << ":" << json.dump();
this->webSocket->send(msg.str(), false);
nlohmann::json json = {
{"altitude", d.alt},
{"vs", d.vs},
{"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 germanairlinesva_websocket
} // namespace 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::simdata::SimDatabase> database;
std::unique_ptr<germanairlinesva_websocket::Websocket> connector;
std::unique_ptr<germanairlinesva::websocket::Websocket> connector;
int xplaneVersion;
/* Datarefs */
@ -43,7 +43,7 @@ XPLMDataRef pitch;
XPLMDataRef roll;
XPLMDataRef quaternion;
struct germanairlinesva_websocket::data toSend;
struct germanairlinesva::websocket::data toSend;
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>();
toLog("Config loaded");
connector = std::make_unique<germanairlinesva_websocket::Websocket>(
connector = std::make_unique<germanairlinesva::websocket::Websocket>(
"wss://ws.hofmannnet.myhome-server.de:8000",
configuration->getUser(),
toLog);
@ -128,18 +128,6 @@ PLUGIN_API int XPluginStart(char *outName, char *outSig, char *outDesc)
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
@ -219,7 +207,7 @@ 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));
std::memset(&toSend, 0, sizeof(germanairlinesva::websocket::data));
toSend.pause = XPLMGetDatai(pauseIndicator);
toSend.pBrake = XPLMGetDataf(parkingBrake);
@ -260,11 +248,11 @@ void serverWorker()
germanairlinesva::util::setThreadName("GAServerWorker");
while (!wantsExit) {
struct germanairlinesva_websocket::data copy;
struct germanairlinesva::websocket::data copy;
{
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);
@ -283,11 +271,11 @@ void recordingWorker()
std::uint32_t segment = 0;
while (!wantsExit) {
germanairlinesva_websocket::data copy;
germanairlinesva::websocket::data copy;
{
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(