While developing a window program, right now; I am dealing with the same issue.
I would “REALLY” like it if MS/Asobo would add a Quarter-Second option to the equates. That would solve many issues for all of us wanting something, pseudo-real-time but would still not cause the processes to go into the medium to very-high status in Task Manager.
Asobo: Please add the quarter-second option to SimConnect updates:
Actually, I am. I am using a separate GUI outside of the data-capture SimConnect program that I wrote (250ms).
It would just be great if Asobo could give us that “one more option” so that you could use any language you want “outside” of a C/C++/C# data capture program.
Not everyone codes in C/C++/C#. I would never use C# to process the thirty-three data values I am showing on my window. C# is not that fast nor ever has been.
I wrote a simplified SimConnect wrapper in C#, it seems to handle the transmission speed without issue or excessive overhead.
It’s still in development but the aim is to obfuscate much of the intricacies and complexities of using SimConnect, just allowing consuming projects to submit a request and receive a response (or responses).
It takes control of handing the windows messages, so it doesn’t require a form, it can connect or disconnect, even via the network, I can request SimVars with or without a frequency, it can submit SimVars with a value, although that’s the part still being developed.
All I am saying is it would be appreciated if Asobo added Quarter-Second processing to the RequestDataOnSimObject() call. For some of us, it would be nice to have this.
The disparity between say: 30fps (SIMCONNECT_PERIOD_SIMFRAME / VISUALFRAME) and one-second (SIMCONNECT_PERIOD_SECOND) is huge. It would be good to give us something in-between, that’s all. Enough said.
The consumers (actually just one in my concrete case) are implemented by me as well (= no third party code that I can‘t control). I do not plan to do any mistakes. But if I do it is my own dog food and I can easily fix it
And yes, I plan to implement the consumer (a „reader“ - which reads the data from the ring buffer and eventually writes it to persistent memory) in a thread.
So together with the „polling loop“ - the „writer“ - this will then be a nice little „reader/writer“ example. And when one designs the ring buffer with a „sentinel“ one can even get away without having to use a mutex
But yes, if that thread goes „boink!“ then so will my entire application (same provess in the end). But that is a risk that I am willing to take - and manage - because as I said, all code is under my control.
I am not too familiar with C#. What exactly differentiates a Task from a thread? Is it some kind of „co-routine“ concept (e.g. Golang has now coroutines as well)? Or simply a „pre-allocated thread“ from a thread pool? Or in analogy to what Java calls „green threads“ (basically threads that are handled/scheduled by the JVM itself, and not the underlying operating system?)
UPDATE: Ah, I think you already gave a hint about „tasks“, I just realised: „ rather than in-process“. So a task is simply a separate process then, correct?
I’ve written code for both implementations, I have my own Client/Server solution in another project.
Although the stand-alone SimConnect helper currently uses the built-in network feature of SimConnect. It can be supplied with an endpoint to connect to or it can parse the SimConnect.XML file of the server (if it’s local) to iterate through every network option until one connects. It also allows me to disconnect if I wish, something you and I have discussed before.
It’s a bit like asking, what is the difference between a function and a sub-routine. You can ask this of 12 different developers and get a dozen different answers but the concept is the same.
A thread is a parallel process that you can fire-and-forget. It typically doesn’t return any values. A task is similar but is typically used to process asynchronously and return a value (although it doesn’t have to).
There are different methods and properties associated with them, I tend to use them depending on how I want them to interact with my main thread, rather than if I want a value returned (although I do use tasks for returning values too).
For example, a task can be cancelled from within the main thread by setting a cancellation token the task was originally called with, a thread needs to be coded to abort in a given situation, such as a while{} loop checking for a change in a static property controlled by the main thread.
Typically, a thread might also use tasks for asynchronous processes but you wouldn’t normally use threads within a task.
I’d like to share my experience here another time, as I have sucessfully build a “win32 event based variable reading”. In my case I am building a C++ application together with a “QWidget-based (Qt) application”, but my code reflects what has been discussed above already and should be easy to generalise to other languages / frameworks.
So in case anyone stumbles across this and wants to see some “real world example code” (with all the usual disclaimers like “it works for me” and “whatever-you-do-it’s-your-fault” etc ;)):
An event-based notification basically boils down to:
When opening the connection SimConnect_Open provide both a HWND (“window handle”) and a “user event identifier”
When intercepting the window events look out for that “user event identifier”: when such an event has been sent…
… then call SimConnect_CallDispatch (which takes a “dispatch procedure” (= callback) as argument which then processes the actually received data/events)
So far so good. But where do we get that “window handle” from? Where to “intercept” the window events?
In fact, the questions are related: the “window handle” (HWND) is to be from the same window (“widget” in Qt speak) which also intercepts the window messages. Typically that is the “main window”, but since in my case I want to keep the “SimConnect code” completely separate from the actual application implementation (in fact, the entire code is going to be “outsourced” into a “plugin” later on) I did not want my “main window” to handle any “SimConnect specific logic”, and I would have add to “pass down” its “window handle” (HWND) to the constructor, polluting also the “interface” (in C++: a header with all pure virtual methods - acts like a “Java interface” class) with Windows-specific headers etc.
Or in other words: within my “SimConnect” logic I create my own QWidget - called the EventWidget - which does nothing more than re-implement the “nativeEvent” method:
So whenever a SimConnnectUserMessage comes in the widget emits a simConnectEvent signal and return true (= “we handled that event”). Otherwise we let the default implementation handle the event (by returning false).
That’s it! We have succesfully “intercepted” our “user message” which is sent by SimConnect whenever SimConnect data/events are ready to be processed.
(If you are not familiar with Qt signals and slots, don’t worry: think of it as a “callback mechanism”, or an “observer/model” kind of implementation: the model notifies all observers via signals, and all observers that have connected the signal to their slots (callbacks) get notified (= their slots (methods, callbacks) get called)
The SimConnnectUserMessage is the same value as also used in various SimConnect examples:
static constexpr int SimConnnectUserMessage = 0x0402;
(I guess the value does not really matter for as long as it lies in some “user range” - but since I simply take the same value 0x0402 here as in the various examples I did not do much more "research into the win32 API documentation here ;)).
Now back in the SkyConnectImpl class we get notified by that signal, because we connect that signal with our processEvents slot:
Again, do not worry too much about this Qt way of “registering a callback”: the take-away here is that we simply call our “processEvents” method each time we receive our user message (SimConnnectUserMessage):
void SkyConnectImpl::processEvents()
{
// Update internal state such as the current “timestamp” etc.
…
// Process system events
::SimConnect_CallDispatch(d->simConnectHandle, SkyConnectImpl::dispatch, this);
}
Finally the SkyConnectImpl::dispatch implements the CALLBACK interface as specified in the SimConnect API documentation and is the same callback that is also used in the “polling” approach.
Finally how do we get that HWND (in a Qt based application)? Well, that is easy, with the winId method (which returns a platform-specific “window ID” or “handle”: in this case a HWND value):
In my application logic the eventWidget acts as a toggle: if it has been constructed we go for an “event-based notification” (and we disable the timer: no polling). Otherwise we use a timer (QTimer) for polling (enabled elsewhere in the code).
So what are the results?
With this “event based processing” I got “samples per second” rates of around 25 - 35. That is exactly the expected range, as FS 2020 renders around the same frames per second on my very mid-range system (an iMac 27" from 2017 ;)).
Note though that I am requesting simulation variable updates per calculated simulated frame (SIMCONNECT_PERIOD_SIM_FRAME) and not per visual frame (SIMCONNECT_PERIOD_VISUAL_FRAME), so those “samples per second” values (up to 35 on my system) absolutely make sense (I probably get quite a bit less visual FPS, but never really bothered to measure them).
And in my case I can still use a “fixed frequency polling” (using a QTimer), and the results match: even when I request variable updates at 60 Hz I still get the same 35 samples per second (“requesting more than what is available does not magically produce more” - even tough sometimes we all wish that this was true ;)).
I hope the above helps those which stumble over the same questions like we had here: the code above shows you both how to implement:
a “polling” approach (timer based, with a fixed frequency)
an “event-based approach”, by letting SimConnect inform us with a “user defined window message”
For my code (C/C++) I am using a sleep(15) in my while loop and I am getting good results with that too. Task Manager is reporting Very Low to Low CPU usage at all times, with 1.5Mb memory overhead. And while the program is running MSFS has not hiccuped at all.
Since you understand SimConnect, are we able to get the four-character Departure and Destination ICAO codes, as strings from SC? There is some debate on FSDevelper on this topic.
Has anyone changed the SimVarWatcher program to include reading string data from the sim?
Ha! That’s funny that you’ve mentioned the ICAO codes (from start and destination), as in fact I was trying to get exactly those a couple of days ago - but I gave up
If you simply search the simulation variables list
for “String” (in the Units column) you get some promising candidates like ATC RUNWAY AIRPORT NAME or possibly also GPS APPROACH AIRPORT ID. But the best I got (I believe with one of the ATC_* variables) was some “string to be translated” (prefixed with TT:, if I remember correctly).
I checked how Little Navmap is treating those strings (I think in the case of ATC MODEL, which also returns a “translatable string”, prefixed with TT:) and it seems that Little Navmap is looking that string up in some “translation database” (either in the FS 2020 installation directory itself, or somehow an “extracted database dump” located in the Little Navmap installation directory itself - at that point I lost interest in those “translatable strings” and did not follow up…).
Anyway, I think no “string simulation variable” gives you easy access to the start and destination airport (as previously selected “on the earth map”, or “programmed into the auto pilot”, because I believe even the “ATC related variables” are only actually populated “once you have spoken with ATC” (?).
The next best thing that came to my mind was using the “facilities” list:
and subscribe to changes therein. As I understand the first time you get an initial set of airports and all sorts of navigation stations etc., and as you fly (and approach your final destination airport) that list is being populated with additional “facilities”.
It should theoretically be possible to derive the ICAO code (where “the closest airport at start” is most likely your starting airport, and the closest airport at the end of the flight the one where you have landed).
I haven’t tried this out yet, but before we discuss this further we should probably create a new discussion thread for this topic
Yeah, it’s a bummer that the SimvarWatcher does not support string variables: for all my “string experiments” above I had to (temporarily) add those variables to my request structure, compile and see what I was getting…
That is too funny that we were basically looking at the same thing! I had not thought about looking how
Alex at LNM is doing his look-ups. He is very approachable so I may quiz him on this. He has been doing this for a while and understands all the tricks.
I may take the easy way out and prompt the user to enter in the ICAO destination code so that I can do a lookup on the METAR data for display. If the variable is set once then they can click on the refresh button multiple times for updates.
Your update: Interesting. Thanks for that value-added-feature!
Enough said. Thanks for your help, and sorry for the derail. It is/was related!
And, since we know that Asobo is reading this and they are bringing up new junior programmers on the sim…
They should re-write SimVarWatcher in a C/C++ version so that top-down programmers like myself can understand the jump arounds going on. I find .Net/C#/VB.Net code hard to follow since they like to hide the code in special “hiddy-spots” in the solution explorer. Yup, that’s my problem, not anyone else’s.
As a C# programmer, I have to agree with you to a certain extent, it can be very confusing and difficult to find that one bit of code being called in a deep-nested routine (until you discover F12 in Visual Studio and the newer “peek” feature).
The old-style of programming, where everything existed in one or 2 “files”, does have some benefit, but there’s also some benefit to separating the code into smaller, bite-sized chunks, in other re-usable “files”.
I’m glad I am not on crack with my opinion about the hidden VS obstacles.
Yup, I’m old-style. Programmers should be able to concentrate on the code, not have to understand and abide by the GUI. MS has always had the affinity of hiding things from users. Just my opinion. And, we cannot do without MS so I am still here, forty years later.
Two old-school developers in agreement - who would have thought? lol
I should clarify, I quite like the modern approach of separating code into smaller, bite-sized chunks, in different classes. It makes the code more readable when you’re focussing on specific objects, but when the code is using (calling) code embedded in other classes, it can become very disjointed.
Then I found you can just “jump” to the code being called via F12 in VS. My only issue with that is, it’s not so easy to navigate back to where you were, or if you’re debugging, it’s difficult to find the current breakpoint your code is paused at.
That’s where using the “peek” context-menu comes in useful, it allows you to preview the called code in-line, but if you don’t have multiple displays or a large, high-res screen, this can be a bit limiting.
I found for development, the simplest approach is to adopt-the old-school approach (all/most code in one place), then when you’re almost ready to release it, separate it into logical classes.
If you’ve developed Unit Tests for your project, it’s relatively simple to verify your code changes haven’t broken anything, but the process of separating code can take a while and feel a bit soul-destroying.
I went into VS and pressed F12. Nuttin. Nada. I had to LOL! It’s not your fault it doesn’t work for me. It has to be the keyboard actuator. I tried to reassign Ctrl+M to “build” and that didn’t work. I continue to press the build button. Sigh. Sorry, off-topic again.
My latest venture of getting data for my Flight Information program is using a combination of VS : C/C++, and I use PureBasic (PB) as my GUI code. It is more work to use PureBasic but it gets me out of VS as fast as I can! I use my VS C/C++ code just to get the data from the sim. I pass that data via memory back into my PB program. It is working great! I have the program out to beta testers as of yesterday.
Long term, for the PureBasic community I would like to convert the “C” SimConnect calls into PB calls. This way more people might be inclined to use PB, a much friendlier environment (IMO), to get/put data. PB is a very easy-to-learn programming language.
My program includes Flight Information, METAR data lookup, audible gear/flaps/approach/fuel/baro call-outs, and Flight Plan Viewer.
It’s been a fun project. It keeps me coding without any responsibilities. If you like it great! If not, delete it…
I find it is very helpful to have active during a flight since I struggle to see the small gauges on the dashboard. VR users may enjoy using it if they cannot see the info clearly.
To use F12, the keyboard cursor must be in the keyword you’re interested in, the keyword will usually highlight with a slightly different background colour:
Pressing F12 will then take you to the definition of that method, property, or variable declaration, even if it’s in another file.
The “Peek” context menu is similar, except it will open the definition as an in-line window, within your code, like below.
The “Build” shortcut is Ctrl-F7, although usually I simply want t run my code in Debug mode, for that I just press F5, which will build/compile your code and launch it.