summaryrefslogtreecommitdiffhomepage
path: root/proto-simconnect/ftnoir_protocol_sc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'proto-simconnect/ftnoir_protocol_sc.cpp')
-rw-r--r--proto-simconnect/ftnoir_protocol_sc.cpp240
1 files changed, 90 insertions, 150 deletions
diff --git a/proto-simconnect/ftnoir_protocol_sc.cpp b/proto-simconnect/ftnoir_protocol_sc.cpp
index f2a9dd14..ca76e0ce 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,10 +13,7 @@
#include "api/plugin-api.hpp"
#include "compat/timer.hpp"
#include "compat/library-path.hpp"
-
-simconnect::simconnect() : hSimConnect(nullptr), should_reconnect(false)
-{
-}
+#include "compat/activation-context.hpp"
simconnect::~simconnect()
{
@@ -26,65 +23,62 @@ simconnect::~simconnect()
void simconnect::run()
{
- HANDLE event = CreateEventA(NULL, FALSE, FALSE, nullptr);
+ HANDLE event = CreateEventA(nullptr, FALSE, FALSE, nullptr);
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")))
+ if (!SUCCEEDED(hr = simconnect_subscribe(handle, 0, "1sec")))
+ qDebug() << "fsx: can't subscribe to frame event:" << (void*)hr;
+ else
{
- qDebug() << "simconnect: can't subscribe to frame event:" << hr;
- }
-
- Timer tm;
- should_reconnect = false;
-
- if (SUCCEEDED(hr))
while (!isInterruptionRequested())
{
- if (should_reconnect)
- break;
+ constexpr int max_idle_ms = 2000;
- if (WaitForSingleObject(event, 100) == WAIT_OBJECT_0)
+ if (WaitForSingleObject(event, max_idle_ms) != WAIT_OBJECT_0)
{
- tm.start();
-
- if (!SUCCEEDED(hr = simconnect_calldispatch(hSimConnect, processNextSimconnectEvent, reinterpret_cast<void*>(this))))
- {
- qDebug() << "simconnect: calldispatch failed:" << hr;
- break;
- }
+ qDebug() << "fsx: timeout reached, reconnecting";
+ break;
}
- else
- {
- const int idle_seconds = tm.elapsed_seconds();
- constexpr int max_idle_seconds = 2;
+ if (reconnect.load(std::memory_order_relaxed))
+ 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);
+ QMutexLocker l(&mtx);
+ (void)simconnect_close(handle);
+ handle = nullptr;
}
- 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";
@@ -92,126 +86,70 @@ void simconnect::run()
CloseHandle(event);
}
-void simconnect::pose( const double *headpose )
+void simconnect::pose(const double* pose, const double*)
{
- // 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);
+ data[Pitch] = (float)-pose[Pitch];
+ data[Yaw] = (float)pose[Yaw];
+ data[Roll] = (float)pose[Roll];
+
+ 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;
+
+ QMutexLocker l(&mtx);
+ if (handle)
+ (void)simconnect_set6DOF(handle,
+ data[TX], data[TY], data[TZ],
+ data[Pitch], data[Roll], data[Yaw]);
}
-#ifdef __GNUC__
-# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-#endif
-
-class ActivationContext
-{
-public:
- ActivationContext(const int resid) :
- ok(false)
- {
- hactctx = INVALID_HANDLE_VALUE;
- actctx_cookie = 0;
- ACTCTXA actx = {};
- actx.cbSize = sizeof(actx);
- actx.lpResourceName = MAKEINTRESOURCEA(resid);
- actx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
-#ifdef _MSC_VER
-# define PREFIX ""
-#else
-# define PREFIX "lib"
-#endif
- static const QString prefix = OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH;
- QString path = prefix + PREFIX "opentrack-proto-simconnect.dll";
- QByteArray name = QFile::encodeName(path);
- actx.lpSource = name.constData();
- hactctx = CreateActCtxA(&actx);
- actctx_cookie = 0;
- 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;
- HANDLE hactctx;
- bool ok;
-};
-
module_status simconnect::initialize()
{
- if (!SCClientLib.isLoaded())
+ if (!library.isLoaded())
{
- ActivationContext ctx(142 + static_cast<int>(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);
- 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(_("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 == NULL) {
- return error("Open function not found in DLL!");
- }
- simconnect_set6DOF = (importSimConnect_CameraSetRelative6DOF) SCClientLib.resolve("SimConnect_CameraSetRelative6DOF");
- if (simconnect_set6DOF == NULL) {
- return error("CameraSetRelative6DOF function not found in DLL!");
- }
- simconnect_close = (importSimConnect_Close) SCClientLib.resolve("SimConnect_Close");
- if (simconnect_close == NULL) {
- return error("Close function not found in DLL!");
- }
+ using ptr = decltype(library.resolve(""));
- simconnect_calldispatch = (importSimConnect_CallDispatch) SCClientLib.resolve("SimConnect_CallDispatch");
- if (simconnect_calldispatch == NULL) {
- 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 == NULL) {
- 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_set6DOF(hSimConnect, virtSCPosX, virtSCPosY, virtSCPosZ, virtSCRotX, virtSCRotZ, virtSCRotY);
-}
-
-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_);
@@ -220,17 +158,19 @@ 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;
- break;
- case SIMCONNECT_RECV_ID_EVENT_FRAME:
- self.handle();
+ qDebug() << "fsx: got quit event";
+ self.reconnect = true;
break;
}
}
-OPENTRACK_DECLARE_PROTOCOL(simconnect, SCControls, simconnectDll)
+QString simconnect::game_name()
+{
+ return tr("FSX / Prepar3D");
+}
+
+OPENTRACK_DECLARE_PROTOCOL(simconnect, simconnect_ui, simconnect_metadata)