400 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::websocket::Websocket> connector;
std::unique_ptr<SimConnect> simConnect;
struct germanairlinesva::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::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::util::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::util::setThreadName("GAServerWorker");
while (!wantsExit) {
simConnect->getStates();
struct germanairlinesva::websocket::data *copy =
new germanairlinesva::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::util::setThreadName("GARecordingWorker");
germanairlinesva::file::recording::RecordingEntry lastPath;
std::uint32_t segment = 0;
auto ap = (*database)["EDDF"];
auto rwys = ap.second;
while (!wantsExit) {
struct germanairlinesva::websocket::data *copy =
new germanairlinesva::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;
}