402 lines
10 KiB
C++
402 lines
10 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::shared_ptr<germanairlinesva::file::config::Config> configuration;
|
|
std::unique_ptr<germanairlinesva::file::simdata::SimDatabase> database;
|
|
std::unique_ptr<germanairlinesva::gaconnector::websocket::Websocket> connector;
|
|
std::unique_ptr<SimConnect> simConnect;
|
|
|
|
struct germanairlinesva::gaconnector::websocket::data toSend;
|
|
germanairlinesva::file::recording::Recording p;
|
|
|
|
// The Window Procedure
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static UINT s_uTaskbarRestart;
|
|
|
|
switch (msg) {
|
|
case WM_CREATE: {
|
|
s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
|
|
break;
|
|
}
|
|
case WM_CLOSE: {
|
|
DestroyWindow(hWnd);
|
|
break;
|
|
}
|
|
case WM_DESTROY: {
|
|
end(hWnd);
|
|
break;
|
|
}
|
|
case TRAY_MESSAGE: {
|
|
switch (lParam) {
|
|
case WM_RBUTTONUP:
|
|
case WM_CONTEXTMENU: {
|
|
createMenu(hWnd);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SIMCONNECT_MESSAGE: {
|
|
if (simConnect != nullptr && simConnect->isConnected()) {
|
|
simConnect->handleMessage();
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
if (msg == s_uTaskbarRestart) {
|
|
addNotifyIcon(hWnd);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return DefWindowProc(hWnd, msg, wParam, lParam);
|
|
}
|
|
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wunused-parameter"
|
|
int WINAPI WinMain(HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPSTR lpCmdLine,
|
|
int nCmdShow)
|
|
{
|
|
WNDCLASS wc;
|
|
ZeroMemory(&wc, sizeof(WNDCLASS));
|
|
HWND hWnd;
|
|
MSG msg;
|
|
|
|
wantsExit.store(false);
|
|
|
|
// Exit if already running
|
|
hWnd = FindWindow(WINDOW_CLASS, WINDOW_CLASS);
|
|
if (hWnd != NULL) {
|
|
toLog("Exiting duplicate");
|
|
return 0;
|
|
}
|
|
|
|
// Clear log
|
|
std::ofstream clearLog(BASE_DIRECTORY "log.txt");
|
|
clearLog.close();
|
|
|
|
// Registering the Window Class
|
|
wc.lpfnWndProc = WndProc;
|
|
wc.hInstance = hInstance;
|
|
wc.lpszClassName = WINDOW_CLASS;
|
|
|
|
if (!RegisterClass(&wc)) {
|
|
toLog("Error window register: " + std::to_string(GetLastError()));
|
|
return 0;
|
|
}
|
|
|
|
// Creating the Window
|
|
hWnd = CreateWindow(WINDOW_CLASS,
|
|
WINDOW_CLASS,
|
|
WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
240,
|
|
120,
|
|
NULL,
|
|
NULL,
|
|
hInstance,
|
|
NULL);
|
|
|
|
if (hWnd == NULL) {
|
|
toLog("Error window create: " + std::to_string(GetLastError()));
|
|
return 0;
|
|
}
|
|
|
|
// Add Notify Icon
|
|
if (!addNotifyIcon(hWnd)) {
|
|
toLog("Error notifyIcon: " + std::to_string(GetLastError()));
|
|
return 0;
|
|
}
|
|
|
|
// Never show window
|
|
// ShowWindow(hWnd, SHOW_OPENWINDOW);
|
|
|
|
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(),
|
|
toLog);
|
|
toLog("WebSocket started");
|
|
|
|
#ifndef MSFS
|
|
PWSTR folder;
|
|
HRESULT result = SHGetKnownFolderPath(FOLDERID_RoamingAppData,
|
|
KF_FLAG_DEFAULT,
|
|
NULL,
|
|
&folder);
|
|
if (SUCCEEDED(result)) {
|
|
size_t origsize = wcslen(folder) + 1;
|
|
size_t convertedChars = 0;
|
|
char *nstring = new char[origsize * 2];
|
|
wcstombs_s(&convertedChars, nstring, origsize * 2, folder, _TRUNCATE);
|
|
|
|
std::string path(nstring);
|
|
path.append("\\Microsoft\\FSX\\scenery.cfg");
|
|
toLog(path);
|
|
|
|
delete[] nstring;
|
|
CoTaskMemFree(folder);
|
|
|
|
char hash[2 * MD5LEN + 1] = "";
|
|
if (germanairlinesva::utilities::generateMD5(path.c_str(), hash, toLog) ==
|
|
0) {
|
|
database = std::make_unique<germanairlinesva::file::simdata::SimDatabase>(
|
|
FSX_VERSION,
|
|
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");
|
|
}
|
|
#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();
|
|
|
|
// Open SimConnect
|
|
simConnect = std::make_unique<SimConnect>(hWnd, toLog, configuration);
|
|
|
|
// Thread for sending data to websocket
|
|
serverThread = std::thread(&serverWorker);
|
|
recordingThread = std::thread(&recordingWorker);
|
|
toLog("Workers started");
|
|
|
|
// The Message Loop
|
|
while (GetMessage(&msg, NULL, 0, 0) > 0) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
// Exit
|
|
toLog("Connector stopped");
|
|
return msg.wParam;
|
|
}
|
|
#pragma clang diagnostic pop
|
|
|
|
WINBOOL addNotifyIcon(HWND hWnd)
|
|
{
|
|
HICON icon;
|
|
NOTIFYICONDATA niData;
|
|
ZeroMemory(&niData, sizeof(NOTIFYICONDATA));
|
|
|
|
icon = (HICON)LoadImage(GetModuleHandle(NULL),
|
|
MAKEINTRESOURCE(APP_ICON),
|
|
IMAGE_ICON,
|
|
GetSystemMetrics(SM_CXSMICON),
|
|
GetSystemMetrics(SM_CYSMICON),
|
|
LR_SHARED);
|
|
if (icon == NULL) {
|
|
toLog("error icon " + std::to_string(GetLastError()));
|
|
}
|
|
niData.cbSize = sizeof(NOTIFYICONDATA);
|
|
niData.uVersion = NOTIFYICON_VERSION_4;
|
|
niData.uID = TRAY_ICON_ID;
|
|
niData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
|
|
strcpy(niData.szTip, "GA Connector");
|
|
niData.hIcon = icon;
|
|
niData.hWnd = hWnd;
|
|
niData.uCallbackMessage = TRAY_MESSAGE;
|
|
|
|
WINBOOL retVal = Shell_NotifyIcon(NIM_ADD, &niData);
|
|
// DestroyIcon(niData.hIcon);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
WINBOOL removeNotifyIcon(HWND hWnd)
|
|
{
|
|
NOTIFYICONDATA niData;
|
|
ZeroMemory(&niData, sizeof(NOTIFYICONDATA));
|
|
|
|
niData.cbSize = sizeof(NOTIFYICONDATA);
|
|
niData.uID = TRAY_ICON_ID;
|
|
niData.hWnd = hWnd;
|
|
return Shell_NotifyIcon(NIM_DELETE, &niData);
|
|
}
|
|
|
|
WINBOOL createMenu(HWND hWnd)
|
|
{
|
|
const int IDM_EXIT = 100;
|
|
POINT pt;
|
|
GetCursorPos(&pt);
|
|
|
|
HMENU hMenu = CreatePopupMenu();
|
|
AppendMenu(hMenu, MF_STRING | MF_GRAYED, NULL, "Version: " BIT " Bit");
|
|
if (simConnect->isConnected()) {
|
|
std::string version("Connected to Sim: ");
|
|
version.append(simConnect->getVersion());
|
|
AppendMenu(hMenu, MF_STRING | MF_GRAYED, NULL, version.c_str());
|
|
}
|
|
AppendMenu(hMenu, MF_SEPARATOR, NULL, NULL);
|
|
AppendMenu(hMenu, MF_STRING, IDM_EXIT, "Exit");
|
|
|
|
SetForegroundWindow(hWnd);
|
|
|
|
WINBOOL cmd = TrackPopupMenu(hMenu,
|
|
TPM_LEFTALIGN | TPM_LEFTBUTTON |
|
|
TPM_BOTTOMALIGN | TPM_RETURNCMD,
|
|
pt.x,
|
|
pt.y,
|
|
0,
|
|
hWnd,
|
|
NULL);
|
|
|
|
if (cmd == IDM_EXIT) {
|
|
PostMessage(hWnd, WM_CLOSE, 0, NULL);
|
|
}
|
|
|
|
return DestroyMenu(hMenu);
|
|
}
|
|
|
|
void end(HWND hWnd)
|
|
{
|
|
removeNotifyIcon(hWnd);
|
|
UnregisterClass(WINDOW_CLASS, GetModuleHandle(NULL));
|
|
|
|
/* End threads */
|
|
wantsExit = true;
|
|
serverThread.join();
|
|
recordingThread.join();
|
|
|
|
p.toFile("flight.rec");
|
|
|
|
// End SimConnect
|
|
delete simConnect.release();
|
|
|
|
PostQuitMessage(0);
|
|
}
|
|
|
|
void serverWorker()
|
|
{
|
|
germanairlinesva::utilities::setThreadName("GAServerWorker");
|
|
|
|
while (!wantsExit) {
|
|
simConnect->getStates();
|
|
|
|
struct germanairlinesva::gaconnector::websocket::data *copy =
|
|
new germanairlinesva::gaconnector::websocket::data();
|
|
{
|
|
const std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
simConnect->getData(copy);
|
|
}
|
|
|
|
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 =
|
|
new germanairlinesva::gaconnector::websocket::data();
|
|
{
|
|
const std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
simConnect->getData(copy);
|
|
}
|
|
|
|
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::ofstream msg(BASE_DIRECTORY "log.txt", std::ofstream::app);
|
|
msg << std::put_time(time, "%Y-%m-%d %H:%M:%S UTC ")
|
|
<< "German Airlines VA: " << message << std::endl;
|
|
} |