Initial start on Recorder
This commit is contained in:
parent
eafe0b18f6
commit
396aa8d807
6
TODO.md
6
TODO.md
@ -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
|
||||
@ -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
180
recorder/recorder.cpp
Normal 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(©, &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(©, &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
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"
|
||||
|
||||
179
xplugin/main.cpp
179
xplugin/main.cpp
@ -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(©,
|
||||
&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(©,
|
||||
&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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user