Has anyone gotten SimConnect to repeatedly get data?

With regards to the issue you found about not seeing the gauges easily on-screen, it’s annoying that you have to keep moving the camera to see them, then jump back to look “out the window”.

For that problem, I’ve been working on another project, to display custom gauges on a separate monitor, or even on another PC.

I’m planning to use the SimConnectHelper as an alternative method of communicating with the FS, so it has a practical use, rather than just used for a tutorial.

1 Like

I have been studying all this and wanted to create an event based call to SimConnect_CallDispatch() rather than use the polling approach. The aim was to do this with plain vanilla Win32 API rather than using managed code so that it would be easier to see what was going on.

HANDLE hEventHandle = ::CreateEvent(NULL, FALSE, FALSE, NULL);

I included the HANDLE hEventHandle in the open call:
SimConnect_Open(&hSimConnect, “Test”, NULL, 0, hEventHandle, SIMCONNECT_OPEN_CONFIGINDEX_LOCAL)

and inserted the following in the polling loop:
if(hEventHandle !=NULL) dw=WaitForSingleObject(hEventHandle, INFINITE);

You need #include <windows.h> of course, but it seems to work a treat. I still don’t really understand what the WM_USER_SIMCONNECT = 0x0402 was all about.

In your case you are implementing your own (blocking!) event loop, using your own event handle. In fact, that is yet another way to fetch simulation variables.

But in case you‘re writing an application with a GUI chances are that you already have an event loop which mostly deals with repaint and user events (mouse, keyboard, …), but of course also listens to other „operating system events“ - such as the custom event that (in the examples above) has been declared with WM_USER_SIMCONNECT.

And in fact it is crucial that one does not block that „application event loop“ with another custom event loop. Unless of course you are dealing with all system/user events yourself and are hence implementing your very own application event loop from scratch. Or in a „non-interactive command line application“, or if your custom event loop would run in its own thread perhaps, or whenever it would be okay to „block user interaction (until the user hits ESC or the like).

So:

  • Use „polling“ (e.g. timer based) and regularly call „dispatch“
  • Implement your own event loop and „wait for events“, with the event handle
  • Let your existing „application event loop“ listen to „custom events“ (WM_USER_SIMCONNECT) that are sent to the window identified by its „hWnd“ („window handle“)

My application does 1) and 3).

My application is a console app and is just proof of concept at the moment to see how far the code can be stripped to the minimum. The plan is to inject aircraft position data. At the moment this is being done with polling and with the FREEZE commands and produces a very smooth flight. The next stage is to try and synch it to the frames by waiting for the frame events.

I am not figuring out how to determine the windows app window handle. I am coding in c++ using a Windows Forms template with Visual Studio. I got polling to work but I would like to try the event driven call to dispatch as well. Any hints on how to get the HWND that I need to pass to simconnect?

Thanks,
Chris

I think I may have answered my own question:

windowhandle = static_cast<HWND>(this->Handle.ToPointer());

I don’t know Windows Forms… but that probably doesn’t matter in this case…
I call the WinAPI function CreateWindow() to initiate the window instance and get the window handle to pass it to my SimConnectOpen function to initiate a SimConnect conncection. The window handle is the return value of the function CreateWindow:

BOOL InitInstance(HINSTANCE hInstance)
{
   hInst = hInstance; 

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }
   SimConnectOpen(hWnd);
   return TRUE;
}

which function do you use to create the window? doesn’t it return its handle?

The window is automatically there when you start a Windows Form. Then you use the form designer to build the elements of the window. This is translated into code in forms.h. Basically it creates a
public ref class Form1 : public System::Windows::Forms::Form

Then in int main() there is :
Application::Run(gcnew CppCLRWinformsProjekt::Form1());

Which is a blocking function. Program is stuck there until you exit. FYI for anyone using Windows Forms, a Load Form event seems to be the best place to put Simconnect initialization routines. Then a Timer_tick event is the best place to put functions that you want to repeat. That is where I put the Simconnect_CallDispatch procedure before I figured out the event driven way of obtaining sim variables. The following code gives me the window handle.

windowhandle = static_cast<HWND>(this->Handle.ToPointer());

Thanks,
Chris

So I am now trying to figure out the best way to obtain a bunch of variables from SimConnect. As far as I have read, there seems to be several methods:

  1. Multiple request ID . → You get a bunch of WM_USER_SIMCONNECT for each data requested. There will be multiple bytes of data including dwData. I think this would be slow.
  2. Request tagged data. → Data comes in pair of identificator int and dwData. However, you are not guaranteed to get the X number of variables you requested. However, the identificator int allows you to sort the variables into the proper bins.
  3. One definition and one request ID → Hopefully, the data in dwData is complete ( no missing variables ) so I can copy using memcpy to an array of double in one operation.

I am leaning towards number 3, but is there an assurance that I get exactly the number of variables that I requested? There is no identificator int here so there would be no way to tell which variable is missing a value.

Any thoughts?

Thanks,
Chris

I tried option 3 but run into a snag. I requested 11 variables and only got 10 back.

int count= (int)pObjData->dwDefineCount; //10 doubles were returned
.....
double dvalue[11];
.....
memcpy(dvalue, x, 88);

However, my request was:

for (int i = 0; i < SimRec.size(); i++) {

		hr = SimConnect_AddToDataDefinition(hSimConnect, SimRec[i].def_ID, SimRec[i].SimVar, SimRec[i].SimUnit);
		
	}
	hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_PACKAGE_1, DEFINITION_PACKAGE_1, SIMCONNECT_SIMOBJECT_TYPE_USER, SIMCONNECT_PERIOD_SIM_FRAME, SIMCONNECT_DATA_REQUEST_FLAG_CHANGED);

And my data definitions are:

array <SimConnectRequest, 11> SimRec = { {
{DEFINITION_PACKAGE_1,"GENERAL ENG THROTTLE LEVER POSITION:1","percent",REQUEST_PACKAGE_1,0},
{DEFINITION_PACKAGE_1,"GENERAL ENG THROTTLE LEVER POSITION:2","percent",REQUEST_PACKAGE_1,0},
{DEFINITION_PACKAGE_1,"LIGHT PANEL ON","Boolean",REQUEST_PACKAGE_1,0},
{DEFINITION_PACKAGE_1,"LIGHT BEACON ON","Boolean",REQUEST_PACKAGE_1,0},
{DEFINITION_PACKAGE_1,"LIGHT CABIN ON","Boolean",REQUEST_PACKAGE_1,0},
{DEFINITION_PACKAGE_1,"LIGHT NAV ON","Boolean",REQUEST_PACKAGE_1,0},
{DEFINITION_PACKAGE_1,"LIGHT TAXI ON","Boolean",REQUEST_PACKAGE_1,0},
{DEFINITION_PACKAGE_1,"LIGHT WING ON","Boolean",REQUEST_PACKAGE_1,0},
{DEFINITION_PACKAGE_1,"LIGHT LANDING ON","Boolean",REQUEST_PACKAGE_1,0},
{DEFINITION_PACKAGE_1,"LIGHT PROBE ON","Boolean",REQUEST_PACKAGE_1,0},
{DEFINITION_PACKAGE_1,"AUTOPILOT HEADING LOCK DIR", "degrees",REQUEST_PACKAGE_1,0}

} };

I am not getting AUTOPILOT HEADING LOCK DIR. Is there a limit to the number of variables that can be defined in a package? The rest of the variables are correct.

Thanks,
Chris

Gosh, might be working too hard.

Just figured out it was a misspelled entry in data definition. LIGHT STROBE ON was spelled as LIGHT PROBE ON. So it wasn’t returning a variable. Curiously though, there was no error on adding the wrong data definition. When I corrected it, I was getting exactly the number of variables back that I requested.

Chris

Is there a way to “tweak” the package definition after it has been sent. For example, delete an entry in the package definition, without actually deleting the entire definition?

Chris

Geeez! How I love the win32 API naming conventions :wink: /off-topic

There is no “client-side” (= your application) validation, neither for simulation variable names, nor on their type.

So you may as well request a variable “Mickey Mouse” with a unit of “Disney”. What will happen is that the server (= the flight simulator) will shrug with its shoulders and send you a nice error reply back (or sort “invalid argument”, “unknown variable” or the like). Or it might even silently ignore your request, not sure right now…

Btw I am not quite sure what you are trying to achieve here, e.g. wheter you want to make your requested data somehow “dynamic” (your follow-up question seems to indicate so), but the usual way to request a “set of variables” is to simply define a struct, e.g.

#pragma pack(push, 1)
struct MyRequestData
{
    double simVariable1;
    double simVariable2;
    double simVariable3;
    int32 someMemberOfDifferentSize;
};
#pragma pack(pop)

Then you would “register” the desired simulation variables with SimConnect_AddToDataDefinition (just as you did), by making sure that the requested type matches in size with the struct members in the struct (e.g. a double is expected to have 64 bit, an int32 has 32 bit etc.)

And pay special attention to the #pragma declaration (compiler specifc directive (*) - not part of the C++ standard): it tells the compiler to “tightly pack” the record in memory (instead of aligning the struct members to memory boundary for best performance). This is because the SimConnect server will return a “blob”: a binary large object aka “opaque buffer of bytes”. And you will “cast” this buffer onto your struct, so the data has to match exactly (something about which I stumbled).

(*) See my posts above: the directive is specific to the MS compiler, but also works with gcc (and probably other compilers, too)

Now you on the other hand are declaring an array of 11 elements of type double. That works for as long as your requested simulation variables will have the size of 64 bit (= the size of a double - which btw. might also be more or less than 64 bit - but since we’re talking “Windows 10 on Intel” let’s assume it is 64 bit ;)). And an array is tightly packed, too.

Now I don’t think that once you have registered a given simulation variable with a given “data definition” group that you can individually remove it again. The only function that I found which “clears” the entire data definition is:

https://docs.flightsimulator.com/html/index.htm#t=Programming_Tools%2FSimConnect%2FAPI_Reference%2FEvents_And_Data%2FSimConnect_ClearDataDefinition.htm

But that’s about it.

So far I haven’t used any variables that are not double. Looking at a bunch of lists on the net, some simvars are stated to return as BCD32 or some other format but I have found out that they are coming back as double. Are there any simulation variables that are not returned as double?

I did try SimConnect_ClearDataDefinition. Thanks. I found out you have to suspend data retrievel with SIMCONNECT_PERIOD_NEVER first, otherwise it crashes the sim.

Sadly, yes. Any that expect location (position) data requires a separate structure (e.g. STRUCT LATLONALT), some expect boolean values (e.g. OVERSPEED WARNING), others still require unsigned integers of various sizes, enums (integers) and so on.

The default data type for most SimVars is FLOAT64 (double), but you do need to use the correct datatype for some SimVars, they’re detailed in the SDK documentation, which is still being updated but does contain most data types now.

I don‘t think that this is quite true: in fact, double - or rather: FLOAT64 - works for everything (all simulation variables) except „string variables“. Hence it is the default data type (argument) in the call to „addToDefinition“ :wink:

But you can specify other types as well, they are defined in the SimConnect.h header.

But the size MUST match with your client types (int, float, double, …), AND your struct members must hence be tightly aligned, too.

Oddly, I can’t argue with that, I was reviewing the documentation relating to Data Types and found that, despite being defined in the SimVar list, there’s no ENUM for any of the BOOL data types.

That seems such a waste of bits, using a 64-bit data type just for a boolean value.

Yeah, I know it’s a fairly minor thing but it just seems like a poor design, likely because of the many iterations the SimConnect SDK has gone through over the years.

I’d love to see documentation relating to the API protocol, so we can bypass SimConnect SDK completely and simplify (maybe even improve) our own SDK interfaces for any language.

Someone has pointed me towards a Java project that attempts to do just this, I’ve reviewing the code to see how easy it will be to port across to C variants.