Initial start on Recorder

This commit is contained in:
Kilian Hofmann 2022-10-04 01:24:15 +02:00
parent eafe0b18f6
commit 396aa8d807
7 changed files with 250 additions and 184 deletions

View File

@ -16,3 +16,9 @@
- hash: Hash of file at path
- Requires mapping akin to C#
- Try to be fast
- Define Protocoll
- Login Master Slave
- Commands
- Text
- Port
- Time

View File

@ -1,6 +1,19 @@
#ifndef GERMANAIRLINESVA_GACONNECTOR_RECORDER_RECORDER_H
#define GERMANAIRLINESVA_GACONNECTOR_RECORDER_RECORDER_H
#include <atomic>
#include <functional>
#include <mutex>
#include <queue>
#include <thread>
#include "websocket.h"
#include "config/config.hpp"
#include "logbook/logbook.hpp"
#include "recording/recording.hpp"
#include "simdata/simDatabase.hpp"
namespace germanairlinesva
{
namespace gaconnector
@ -9,6 +22,38 @@ namespace gaconnector
{
class Recorder
{
private:
std::function<void(const std::string)> toLog;
std::mutex mutex;
std::thread serverThread;
std::thread recordingThread;
std::atomic<bool> wantsExit{false};
std::shared_ptr<file::config::Config> configuration;
std::unique_ptr<file::simdata::SimDatabase> database;
std::unique_ptr<websocket::Websocket> connector;
websocket::data toSend;
std::queue<std::function<void()>> &messageQueue()
{
static std::queue<std::function<void()>> _messageQueue;
return _messageQueue;
}
void serverWorker();
void recordingWorker();
// For Testing
void test() const;
public:
Recorder(int simVersion, std::function<void(const std::string)> toLog);
~Recorder();
void setData(websocket::data &data);
void handleMessages();
};
} // namespace recorder
} // namespace gaconnector

180
recorder/recorder.cpp Normal file
View File

@ -0,0 +1,180 @@
#include "include/recorder.h"
namespace germanairlinesva
{
namespace gaconnector
{
namespace recorder
{
Recorder::Recorder(int simVersion,
std::function<void(const std::string)> toLog)
: toLog(std::move(toLog))
{
// Configuration
this->configuration = std::make_shared<file::config::Config>();
this->toLog("Configuration loaded");
// Database
#ifdef XP
char hash[2 * MD5LEN + 1] = "";
if (utilities::generateMD5(XPLANE_CUSTOM_SCENERY, hash, toLog) == 0) {
this->database =
std::make_unique<file::simdata::SimDatabase>(simVersion,
hash,
this->configuration,
this->toLog);
}
#endif
#ifndef MSFS
#endif
// WebSocket
this->connector = std::make_unique<websocket::Websocket>(
"wss://ws.hofmannnet.myhome-server.de:8000",
this->configuration->getUser(),
this->toLog);
this->toLog("WebSocket started");
// For Testing
this->test();
// Thread for sending data to websocket
this->serverThread = std::thread(&Recorder::serverWorker, this);
this->recordingThread = std::thread(&Recorder::recordingWorker, this);
this->toLog("Workers started");
}
Recorder::~Recorder()
{
wantsExit = true;
serverThread.join();
recordingThread.join();
}
void Recorder::setData(websocket::data &data)
{
const std::lock_guard<std::mutex> lock(mutex);
std::memcpy(&this->toSend, &data, sizeof(websocket::data));
}
void Recorder::handleMessages()
{
const std::lock_guard<std::mutex> lock(mutex);
if (!messageQueue().empty()) {
auto op = std::move(messageQueue().front());
messageQueue().pop();
op();
}
}
void Recorder::serverWorker()
{
utilities::setThreadName("GAServerWorker");
while (!wantsExit) {
struct websocket::data copy;
{
const std::lock_guard<std::mutex> lock(mutex);
std::memcpy(&copy, &toSend, sizeof(websocket::data));
}
connector->sendData(copy);
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
toLog("Server thread stopped");
}
void Recorder::recordingWorker()
{
utilities::setThreadName("GARecordingWorker");
file::recording::Recording path;
file::recording::RecordingEntry lastPath;
std::uint32_t segment = 0;
while (!wantsExit) {
struct websocket::data copy;
{
const std::lock_guard<std::mutex> lock(mutex);
std::memcpy(&copy, &toSend, sizeof(websocket::data));
}
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) {
path.addEntry(currentPath);
lastPath = currentPath;
}
segment++;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
path.toFile("flight.rec");
toLog("Recording thread stopped");
}
void Recorder::test() const
{
#ifndef MSFS
this->toLog("Readback test of sim database using EDDF");
auto ap = (*this->database)["EDDF"];
for (const auto &it : ap.first) {
this->toLog(" " + it.to_string());
}
for (const auto &it : ap.second) {
this->toLog(" " + it.to_string());
}
this->toLog("Readback test of sim database using XXXX");
auto ap2 = (*database)["XXXX"];
ap2.first.size() == 0 ? this->toLog(" SUCCESS") : this->toLog(" ERROR");
#endif
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();
}
} // namespace recorder
} // namespace gaconnector
} // namespace germanairlinesva

View File

@ -91,7 +91,7 @@ namespace gaconnector
if (strcmp(d.path, this->lastPath) != 0) {
strcpy(this->lastPath, d.path);
if (utilities::generateMD5(d.path, this->lastHash, this->toLog)) {
strcpy(this->lastHash, "NOT SET");
strcpy(this->lastHash, "NO HASH");
}
}

View File

@ -1,12 +1,15 @@
file(GLOB socket CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/websocket/*.cpp)
file(GLOB recorder CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/recorder/*.cpp)
add_library(germanairlinesva_xplugin SHARED
${socket}
${recorder}
main.cpp
)
target_include_directories(germanairlinesva_xplugin PRIVATE
${CMAKE_SOURCE_DIR}/file/include
${CMAKE_SOURCE_DIR}/recorder/include
${CMAKE_SOURCE_DIR}/simdata/include
${CMAKE_SOURCE_DIR}/websocket/include
${CMAKE_SOURCE_DIR}/utilities/include

View File

@ -1,24 +1,13 @@
#ifndef GERMANAIRLINESVA_GACONNECTOR_XPLUGIN_MAIN_H
#define GERMANAIRLINESVA_GACONNECTOR_XPLUGIN_MAIN_H
#include <atomic>
#include <chrono>
#include <cstdint>
#include <ctime>
#include <iomanip>
#include <mutex>
#include <queue>
#include <sstream>
#include <string>
#include <thread>
#include "websocket.h"
#include "config/config.hpp"
#include "constants.h"
#include "logbook/logbook.hpp"
#include "recording/recording.hpp"
#include "simdata/simDatabase.hpp"
#include "util.hpp"
#include "recorder.h"
#include "XPLM/XPLMDataAccess.h"
#include "XPLM/XPLMGraphics.h"

View File

@ -1,20 +1,5 @@
#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::shared_ptr<germanairlinesva::file::config::Config> configuration;
std::unique_ptr<germanairlinesva::file::simdata::SimDatabase> database;
std::unique_ptr<germanairlinesva::gaconnector::websocket::Websocket> connector;
int xplaneVersion;
/* Datarefs */
XPLMDataRef pauseIndicator;
XPLMDataRef parkingBrake;
@ -44,21 +29,20 @@ XPLMDataRef roll;
XPLMDataRef quaternion;
struct germanairlinesva::gaconnector::websocket::data toSend;
germanairlinesva::file::recording::Recording p;
germanairlinesva::gaconnector::recorder::Recorder *recorder;
/*
* Callbacks
*/
PLUGIN_API int XPluginStart(char *outName, char *outSig, char *outDesc)
{
int xplaneVersion;
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. */
@ -111,77 +95,10 @@ PLUGIN_API int XPluginStart(char *outName, char *outSig, char *outDesc)
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::gaconnector::websocket::Websocket>(
"wss://ws.hofmannnet.myhome-server.de:8000",
configuration->getUser(),
// Recorder
recorder =
new germanairlinesva::gaconnector::recorder::Recorder(xplaneVersion,
toLog);
toLog("WebSocket started");
char hash[2 * MD5LEN + 1] = "";
if (germanairlinesva::utilities::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;
}
@ -190,12 +107,9 @@ PLUGIN_API void XPluginStop(void)
{
/* Flight Loop */
XPLMUnregisterFlightLoopCallback(flightLoop, nullptr);
/* End threads */
wantsExit = true;
serverThread.join();
recordingThread.join();
p.toFile("flight.rec");
/* End threads */
recorder->~Recorder();
toLog("Plugin stopped");
}
@ -216,8 +130,6 @@ PLUGIN_API void
#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::gaconnector::websocket::data));
@ -246,83 +158,14 @@ float flightLoop(float elapsedMe, float elapsedSim, int counter, void *refcon)
toSend.payloadKg = XPLMGetDataf(payloadKgs);
toSend.totalWeightKg = XPLMGetDataf(totalWeightKgs);
if (!messageQueue().empty()) {
auto op = std::move(messageQueue().front());
messageQueue().pop();
op();
}
recorder->setData(toSend);
recorder->handleMessages();
return -1;
}
#pragma clang diagnostic pop
void serverWorker()
{
germanairlinesva::utilities::setThreadName("GAServerWorker");
while (!wantsExit) {
struct germanairlinesva::gaconnector::websocket::data copy;
{
const std::lock_guard<std::mutex> lock(mutex);
std::memcpy(&copy,
&toSend,
sizeof(germanairlinesva::gaconnector::websocket::data));
}
connector->sendData(copy);
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
toLog("Server thread stopped");
}
void recordingWorker()
{
germanairlinesva::utilities::setThreadName("GARecordingWorker");
germanairlinesva::file::recording::RecordingEntry lastPath;
std::uint32_t segment = 0;
auto ap = (*database)["EDDF"];
auto rwys = ap.second;
while (!wantsExit) {
struct germanairlinesva::gaconnector::websocket::data copy;
{
const std::lock_guard<std::mutex> lock(mutex);
std::memcpy(&copy,
&toSend,
sizeof(germanairlinesva::gaconnector::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);