diff options
Diffstat (limited to 'proto-simconnect/ftnoir_protocol_sc.cpp')
-rw-r--r-- | proto-simconnect/ftnoir_protocol_sc.cpp | 216 |
1 files changed, 92 insertions, 124 deletions
diff --git a/proto-simconnect/ftnoir_protocol_sc.cpp b/proto-simconnect/ftnoir_protocol_sc.cpp index bd7f0960..9a1db9b5 100644 --- a/proto-simconnect/ftnoir_protocol_sc.cpp +++ b/proto-simconnect/ftnoir_protocol_sc.cpp @@ -2,8 +2,8 @@ * * * ISC License (ISC) * * * - * Copyright (c) 2015, Wim Vriend - * Copyright (c) 2014, Stanislaw Halik <sthalik@misaki.pl> + * Copyright (c) 2015, Wim Vriend * + * Copyright (c) 2014, 2017, 2019 Stanislaw Halik * * * * Permission to use, copy, modify, and/or distribute this software for any * * purpose with or without fee is hereby granted, provided that the above * @@ -13,6 +13,7 @@ #include "api/plugin-api.hpp" #include "compat/timer.hpp" #include "compat/library-path.hpp" +#include "compat/activation-context.hpp" simconnect::~simconnect() { @@ -26,61 +27,61 @@ void simconnect::run() if (event == nullptr) { - qDebug() << "simconnect: event create" << GetLastError(); + qDebug() << "fsx: create event failed, error code" << GetLastError(); return; } + constexpr unsigned sleep_time = 5; + while (!isInterruptionRequested()) { HRESULT hr; + reconnect = false; + handle = nullptr; - if (SUCCEEDED(hr = simconnect_open(&hSimConnect, "opentrack", nullptr, 0, event, 0))) + if (!SUCCEEDED(hr = simconnect_open(&handle, "opentrack", nullptr, 0, event, 0))) + qDebug() << "fsx: connect failed, retry in" << sleep_time << "seconds..."; + else { - if (!SUCCEEDED(hr = simconnect_subscribetosystemevent(hSimConnect, 0, "Frame"))) - { - qDebug() << "simconnect: can't subscribe to frame event:" << hr; - } - Timer tm; - should_reconnect = false; - if (SUCCEEDED(hr)) + if (!SUCCEEDED(hr = simconnect_subscribe(handle, 0, "Frame"))) + qDebug() << "fsx: can't subscribe to frame event:" << (void*)hr; + else + { while (!isInterruptionRequested()) { - if (should_reconnect) - break; + constexpr int max_idle_seconds = 2; - if (WaitForSingleObject(event, 100) == WAIT_OBJECT_0) - { + if (WaitForSingleObject(event, 0) == WAIT_OBJECT_0) tm.start(); - if (!SUCCEEDED(hr = simconnect_calldispatch(hSimConnect, processNextSimconnectEvent, reinterpret_cast<void*>(this)))) - { - qDebug() << "simconnect: calldispatch failed:" << hr; - break; - } - } - else + if ((int)tm.elapsed_seconds() > max_idle_seconds) { - const int idle_seconds = tm.elapsed_seconds(); + qDebug() << "fsx: timeout reached, reconnecting"; + break; + } - constexpr int max_idle_seconds = 2; + if (reconnect) + break; - if (idle_seconds >= max_idle_seconds) - { - qDebug() << "simconnect: reconnect"; - break; - } + if (!SUCCEEDED(hr = simconnect_calldispatch(handle, event_handler, (void*)this))) + { + qDebug() << "fsx: calldispatch failed:" << (void*)hr; + break; } - } + } + } - (void) simconnect_close(hSimConnect); + (void)simconnect_close(handle); } - else - qDebug() << "simconnect: can't open handle:" << hr; - if (!isInterruptionRequested()) - Sleep(3000); + for (unsigned k = 0; k < sleep_time * 25; k++) + { + if (isInterruptionRequested()) + break; + Sleep(1000 / 25); + } } qDebug() << "simconnect: exit"; @@ -88,112 +89,74 @@ void simconnect::run() CloseHandle(event); } -void simconnect::pose( const double *headpose ) +void simconnect::pose(const double* pose) { - // euler degrees - virtSCRotX = float(-headpose[Pitch]); - virtSCRotY = float(headpose[Yaw]); - virtSCRotZ = float(headpose[Roll]); - - // cm to meters - virtSCPosX = float(-headpose[TX]/100); - virtSCPosY = float(headpose[TY]/100); - virtSCPosZ = float(-headpose[TZ]/100); -} + QMutexLocker l(&mtx); -#ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#endif + data[Pitch] = (float)-pose[Pitch]; + data[Yaw] = (float)pose[Yaw]; + data[Roll] = (float)pose[Roll]; -class ActivationContext -{ -public: - explicit ActivationContext(int resid) - { - ACTCTXA actx = {}; - actx.cbSize = sizeof(actx); - actx.lpResourceName = MAKEINTRESOURCEA(resid); - actx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; - static const QString prefix = OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH; - QString path = prefix + "lib" "opentrack-proto-simconnect.dll"; - QByteArray name = QFile::encodeName(path); - actx.lpSource = name.constData(); - hactctx = CreateActCtxA(&actx); - if (hactctx != INVALID_HANDLE_VALUE) - { - if (!ActivateActCtx(hactctx, &actctx_cookie)) - { - qDebug() << "simconnect: can't set win32 activation context" << GetLastError(); - ReleaseActCtx(hactctx); - hactctx = INVALID_HANDLE_VALUE; - } - else - ok = true; - } else { - qDebug() << "simconnect: can't create win32 activation context" << GetLastError(); - } - } - ~ActivationContext() { - if (hactctx != INVALID_HANDLE_VALUE) - { - DeactivateActCtx(0, actctx_cookie); - ReleaseActCtx(hactctx); - } - } - bool is_ok() const { return ok; } - -private: - ULONG_PTR actctx_cookie = 0; - HANDLE hactctx = INVALID_HANDLE_VALUE; - bool ok = false; -}; + constexpr float to_meters = 1e-2f; + data[TX] = (float)-pose[TX] * to_meters; + data[TY] = (float)pose[TY] * to_meters; + data[TZ] = (float)-pose[TZ] * to_meters; +} module_status simconnect::initialize() { - if (!SCClientLib.isLoaded()) + if (!library.isLoaded()) { - ActivationContext ctx(142 + s.sxs_manifest); + constexpr int resource_offset = 142; + activation_context ctx("opentrack-proto-simconnect" "." OPENTRACK_LIBRARY_EXTENSION, + resource_offset + s.sxs_manifest); - if (ctx.is_ok()) + if (ctx) { - SCClientLib.setFileName("SimConnect.dll"); - SCClientLib.setLoadHints(QLibrary::PreventUnloadHint | QLibrary::ResolveAllSymbolsHint); - if (!SCClientLib.load()) - return error(tr("dll load failed -- %1").arg(SCClientLib.errorString())); + library.setFileName("SimConnect.dll"); + library.setLoadHints(QLibrary::PreventUnloadHint | QLibrary::ResolveAllSymbolsHint); + if (!library.load()) + return error(tr("dll load failed: %1").arg(library.errorString())); } else - return error(tr("can't load SDK -- check selected simconnect version")); + // XXX TODO add instructions for fsx and p3d -sh 20190128 + return error(tr("Install FSX/Prepar3D SimConnect SDK.")); } - simconnect_open = (importSimConnect_Open) SCClientLib.resolve("SimConnect_Open"); - if (!simconnect_open) - return error("Open function not found in DLL!"); - simconnect_set6DOF = (importSimConnect_CameraSetRelative6DOF) SCClientLib.resolve("SimConnect_CameraSetRelative6DOF"); - if (!simconnect_set6DOF) - return error("CameraSetRelative6DOF function not found in DLL!"); - simconnect_close = (importSimConnect_Close) SCClientLib.resolve("SimConnect_Close"); - if (!simconnect_close) - return error("Close function not found in DLL!"); + using ptr = decltype(library.resolve("")); - simconnect_calldispatch = (importSimConnect_CallDispatch) SCClientLib.resolve("SimConnect_CallDispatch"); - if (!simconnect_calldispatch) - return error("CallDispatch function not found in DLL!"); + struct { + const char* name; + ptr& place; + } list[] = { + { "SimConnect_Open", (ptr&)simconnect_open }, + { "SimConnect_CameraSetRelative6DOF", (ptr&)simconnect_set6DOF }, + { "SimConnect_Close", (ptr&)simconnect_close }, + { "SimConnect_CallDispatch", (ptr&)simconnect_calldispatch }, + { "SimConnect_SubscribeToSystemEvent", (ptr&)simconnect_subscribe }, + }; - simconnect_subscribetosystemevent = (importSimConnect_SubscribeToSystemEvent) SCClientLib.resolve("SimConnect_SubscribeToSystemEvent"); - if (!simconnect_subscribetosystemevent) - return error("SubscribeToSystemEvent function not found in DLL!"); + for (auto& x : list) + { + x.place = library.resolve(x.name); + if (!x.place) + return error(tr("can't import %1: %2").arg(x.name, library.errorString())); + } start(); - return status_ok(); + return {}; } -void simconnect::handle() +void simconnect::handler() { - (void) simconnect_set6DOF(hSimConnect, virtSCPosX, virtSCPosY, virtSCPosZ, virtSCRotX, virtSCRotZ, virtSCRotY); + QMutexLocker l(&mtx); + (void)simconnect_set6DOF(handle, + data[TX], data[TY], data[TZ], + data[Pitch], data[Roll], data[Yaw]); } -void CALLBACK simconnect::processNextSimconnectEvent(SIMCONNECT_RECV* pData, DWORD, void *self_) +void simconnect::event_handler(SIMCONNECT_RECV* pData, DWORD, void* self_) { simconnect& self = *reinterpret_cast<simconnect*>(self_); @@ -202,17 +165,22 @@ void CALLBACK simconnect::processNextSimconnectEvent(SIMCONNECT_RECV* pData, DWO default: break; case SIMCONNECT_RECV_ID_EXCEPTION: - qDebug() << "simconnect: got exception"; - //self.should_reconnect = true; + // CAVEAT: can't reconnect here, it breaks Prepar3D. + // the timer on the event handle will take care of failures. break; case SIMCONNECT_RECV_ID_QUIT: - qDebug() << "simconnect: got quit event"; - self.should_reconnect = true; + qDebug() << "fsx: got quit event"; + self.reconnect = true; break; case SIMCONNECT_RECV_ID_EVENT_FRAME: - self.handle(); + self.handler(); break; } } -OPENTRACK_DECLARE_PROTOCOL(simconnect, SCControls, simconnectDll) +QString simconnect::game_name() +{ + return tr("FSX / Prepar3D"); +} + +OPENTRACK_DECLARE_PROTOCOL(simconnect, simconnect_ui, simconnect_metadata) |