• Which the release of FS2020 we see an explosition of activity on the forun and of course we are very happy to see this. But having all questions about FS2020 in one forum becomes a bit messy. So therefore we would like to ask you all to use the following guidelines when posting your questions:

    • Tag FS2020 specific questions with the MSFS2020 tag.
    • Questions about making 3D assets can be posted in the 3D asset design forum. Either post them in the subforum of the modelling tool you use or in the general forum if they are general.
    • Questions about aircraft design can be posted in the Aircraft design forum
    • Questions about airport design can be posted in the FS2020 airport design forum. Once airport development tools have been updated for FS2020 you can post tool speciifc questions in the subforums of those tools as well of course.
    • Questions about terrain design can be posted in the FS2020 terrain design forum.
    • Questions about SimConnect can be posted in the SimConnect forum.

    Any other question that is not specific to an aspect of development or tool can be posted in the General chat forum.

    By following these guidelines we make sure that the forums remain easy to read for everybody and also that the right people can find your post to answer it.

FSXA Simconnect Gauges

mendiola_loyola

Resource contributor
Messages
520
Country
peru
Dear All:

Is there an example or tutorial about simmconect gauges c++?

Do i have to use the singleton pattern?

Thanks.
Alfredo Mendiola Loyola
Lima, Perú
 
I don't use a singleton pattern (as far as you would recognise it in C++) because I create the simconnect interface in the pre-initialise callback, service it in the pre-update and close it in the quit callbacks and put an "if" around the functions that check the state of a global variable that's set up when the SimConnect interface is still opened.

I've always tried to stay clear of using C++ class structures in gauges as they just don't fit the very C-styled paradigm of the macro driven gauge system. (But that's not to say you couldn't and it might be more elegant if done well.)

Si
 
Connecting Gauges to Simconnect

Dear mendiola_loyola and Simon853,

Its possible to send data from my 'custom gauge' to simconnect??

and what is the mean of 'the singleton pattern'

best regards,

bluejoystick
 
The Singleton Pattern is an object-oriented design pattern than ensures that the program can only ever create one instance of a module no matter how many times its constructor is called. If you don't know about object-oriented design and/or C++ then there's probably no need for you to worry about it.

Yes, you can send data from a C gauge to a SimConnect application. Look at the SimConnect functions for shared data area. Or you might find it easier just to open a TCP/IP channel depending on your familiarity with Windoews SDK or FSX SDK.

Si
 
Considering that I wrote most of the basis of what ended up to be the GDI+/C++ sample for Microsoft included in the ESP SDK (that code is derived from the F/A-18), I might probably be able to reply to this...

I don't use a singleton pattern (as far as you would recognise it in C++)

That doesn't really have much to do with the use of the Singleton pattern or not. Using the Singleton pattern is really optional, and it's only a way to enforce the use of something that is instantiable only once.

Meaning: you don't run the risk of declaring global variables twice, don't run the risk of opening Simconnect twice, etc.

This is very appropriate for two things: the whole set of data that is retrieved from FSX ( the Simvars ) AND the Simconnect initialization and closure IS inherently something that exist in one copy only, and it's global by nature.

You don't have *two* sets of Simvars, and you don't need (and don't want) open Simconnect twice so, the Singleton is just a way to ensure you CAN'T do that, not even by mistake, because even if you TRY to create another instance of a Singleton, you'll get the another pointer to the object you already created, without creating the object again. That's the whole idea of the Singleton pattern.

However, that's just the beginning of the story. The MS Example has been streamlined a bit, and the Singleton is used ONLY to deal with Simconnect, which is fine for that sample, that is very short.

The Singleton, instead (at least in the F/A-18 code), was mainly used to handle all the "Simulation" in a SINGLE place, trying to obey to those basic design rules:

1) Put everything that deals with "poking FSX" and interfacing with it, in a SINGLE PLACE.

2) Don't read FSX variables in the Gauges. The Gauges should read data ONLY from the Singleton.

This way, the complexity is kept all in a single place. The actual Gauge code only does what is supposed to do: draw items depending on data variables that are read, retrieved or in any other way calculated, somehwere else. In the Singleton, obviously.

The Gauge code shouldn't remotely involved in, let's say, calculate the ETA of arrival at a waypoint and the estimated fuel on arrival. This is something that should be done in a place were some kind of "simulation" is running, and it's the Singleton as well. The Gauge that will *display* the result of that calculation, will just take that value, and display it, as dumbly as possible.

The Gauge shouldn't also be concerned if a variable is coming from FSX Simvars or it's an user created var, or it's something that comes from the GPS.DLL, or it's coming from the 3D model interaction ( an L: var used to create custom animations ).

From the Gauge point of view, they are ALL variables, which can be usually read and, sometimes, can be also written, depending on what WE decide, using access properties and member functions in the Singleton.

The Singleton pattern it's just the "C++ way" to create global variables. We all know that globals are "evil" but, as far as a gauge or any FSX program, Flight Sim variables ARE globals, from the point of view of our program.

Since it's very easy they'll eventually work together with our own created variables, and are inherently globals in nature, our own variables might end up being use like globals as well so, by using the Singleton pattern, we obtain the following:

1) We have a common place were variables that are read from "outside" our program ( the FSX Simvars, obviously ) AND variable that we create, can be together at disposal of the Gauges to be used.

2) Even if the Variables inside the Singleton object are Globals ( of course, assuming the *pointer* to the Singleton object has been declared as a global variable ), we can use what C++ provides in terms of data access protection.

Why a Global variable is usually considered "evil" ? Most of the time, because you don't know who can write to it. Most of the bugs happens when a global variable is used in two places for different uses. BUT, since our Globals are not *real* globals, but the only thing that is really global is the pointer to the Singleton object, using the C++ access function, we can easily specify what can be read/write and what can't.

By declaring a variable "private" in the Singleton class, and providing only a member function to retrieve its value, but no member function to write it, we forced the "global" variable to behave like a read-only property so, we get the convenicence of a value available from everywhere, but we can't screw up with it, because it's read-only...

But, as I've said, the Singleton is not really the "meat" of that example. It would be probably overkill JUST to open Simconnect but, I guess that sample was purposely made that way, because the program is very short.

You really start to appreciate the advantage of using C++ patterns, when the program becomes BIG, like a complex airplane with hundreds/thousands of different variables.

That sample is just a modifed version of a "skeleton" program that makes sense for a large project like a whole airplane.

I've always tried to stay clear of using C++ class structures in gauges as they just don't fit the very C-styled paradigm of the macro driven gauge system. (But that's not to say you couldn't and it might be more elegant if done well.)

Well...it's exactly the opposite: the "very C-styled" paradigm of the Gauge system, it's a way to simulate object orientation without having it, because it was written in C a long time ago, around FS6. It has evolved during the years, but the basic foundation is still there.

But, if you think about it, the static parts of the Gauge that are compiled (bitmaps, icons, etc), are instantiated during run time, just AS IF they were "templates" for the actual gauge. It's OOP without an OOP language so, it SCREAMS to be wrapped in C++.

What really makes that sample Object oriented, however, it's not the use of the Singleton, but more the fact that the Gauge callback are declared as a C++ Template, and the *actual* Gauge is a class derived from that, and both the actual Callback AND the Callback states, are implemented as Virtual functions so, you have a DoCallbak, an OnDraw, an OnGenerate, etc...

In fact, the original C++ wrapper does MUCH more that what is found in that sample so, it included all sort of helper functions to ease GDI+ usage, without having to rewrite the wheel each time so, all the gauges derived from that class would automatically get GDI+ support capabilities and ready to use canvases, automatic background bitmaps handling in case of GDI+ on *top* of a bitmapped background (which is commonly tought to be not possible) to create GDI+ analog instruments with GDI+ needles, etc...


because I create the simconnect interface in the pre-initialise callback, service it in the pre-update and close it in the quit callbacks and put an "if" around the functions that check the state of a global variable that's set up when the SimConnect interface is still opened.

mmmhh, the very usage of such an "if" command, makes for a potentially messy code, and of course we all know that globals are "evil" (without proper treatment, as I've said before).

A better way to open Simonnect, assuming you don't want to use the Singleton and you don't want to use C++, would be to put SimConnect_Open inside your module_init() function, and SimConnect_Close inside the module_deinit() function.

This way, you don't have to use any "if", you don't have to use any global variable in order to check you don't try to open Simconnect twice, and you don't need to worry about having Simconnect not being open at start, because the user has saved a flight in outside view (or any other view that doesn't have that Gauge in the panel ) so, the sub-Gauge you have SimConnect_Open in will never be called until the user goes back to a view that contains that sub-Gauge, possibly creating unexpected results.

Instead, by opening Simconnect in the module_init() and closing it in module_deinit(), you can be 100% sure that this function will be called ONLY ONCE, when loading the AIRPLANE, regardless if the actual sub-gauge is in view or not, because module_init is always called as long the selected airplane has a panel.cfg that contains *any* reference to the main Gauge, even if it's on a panel that is not visible, or the airplane is loaded from an outside view. The same is true for module_deinit(): it's called ONLY when you unload that airplane, either because you selected another one, or because you just quit FSX.

That's why those are the safest places to initialize *everything*, which includes of course your own variables. Which, of course, can be done in the Singleton. And, what better place would be, other than the Singleton's constructor ?

That's why the ::Instance(), which is the "fake" Singleton constructor (we already said, the *real* one can't be accessed, because this is a Singleton), it's called in the module_init() function. So, you can have a very easy to read module_init(), that basically just contains the Singleton instantiation, and you do all the initialization stuff (including Simconnect, but not only...) INSIDE the Singleton so, you get foolproof check agains double initializations, guaranteed that your initalizations WILL be called only once, guarantee that you de-initialization will be called only once, you get everything you need...

See, when you start reasoning in C++ terms, everything will fall in place...
 
Last edited:
Dear Virtuali:

Is it possible to create a thread in the function void FSAPI module_init(void) to manage all the simconnect callback processing (void CALLBACK SampleGauge_DispatchProcDLL(SIMCONNECT_RECV* pData, DWORD cbData, void *pContext)) in order to use another cpu core and improve performance?

Alfredo Mendiola Loyola
Lima, Perú
 
Last edited:
Virtuali, is the ESP available as a download. From the site's I've been to it appears that it's available from the MSDN but that's an expensive subscription (well worth it I feel but can't do it at this time).

Thanks.
 
Virtuali, is the ESP available as a download. From the site's I've been to it appears that it's available from the MSDN but that's an expensive subscription (well worth it I feel but can't do it at this time).

Thanks.

Actually, ESP is no longer available at all... It was killed when ACES was disbanded.
 
Back
Top