February 2022 update: Dynamic data definitions

It’s been a busy month, but mostly in my day job. As you may know, I work as a software architect and developer by day, but that is mostly in Java. (Gasp!) Nevertheless, I did manage to get some important refactoring work done, which was caused by my promise to take a look at my C++ code for generating gauges on the Saitek Flight Instrument Panel. The thing is, data is shown on gauges using scripting, using a stack-oriented language, which is actually used a lot more than you might know. (more later) Lockheed Martin’s Prepar3D added to this the possibility to use LUA, but the important upshot is that you need to parse or even run those scripts to find out which variables you need to ask from the simulator.

I started out with the static alternative, using annotated fields and properties, which CsSiMConnect scans using Reflection. Now we need to be able to add variables “by hand,” which means we can try to find commonality between those two different approaches. The last thing we should do is give up and explicitly expose the convoluted “SimConnect_AddToDataDefinition” approach.

What flows do we want?

I started out with the annotation-based workflow, where you define classes and annotate fields or properties so they match up with variables from the simulator. This makes it very easy to request data because you can just tell the DataManager that you want it to request a certain predefined object in many locations and many times, without having to detail those variables every time. This is an approach I learned from the persistence tooling, where you map a class to a table, and the fields to the columns.

We now get a second flow, where we don’t know the details of the variables to request in advance. There are two ways you can detail that flow:

  1. Request the set of variables and have callbacks for every row (or even individual fields), and
  2. Request the set of variables and get an iterator where you can call “GetInteger”, “GetString”, and so on, to retrieve the individual fields.

So far I have made a start with the first, which looks like this:

DynamicObjectDefinition data = new();
data.AddField("SIM ON GROUND", type: DataType.Int32,
             valueSetter: (bool onGround) => {
                  Console.WriteLine($"SIM ON GROUND = {onGround}");
             });
DataManager.Instance.RequestDynamicData(data);

I agree “DynamicObjectDefinition” is not a good name; probably something like “SimData” is better. This now works and will work just as well when requested with the period set to once per frame and “onlyWhenChanged” set to true. Still to be added is some state management, so you can cancel/end the subscription. The second version comes next and should work in a foreach loop.

Going forward

This is just a short update, but I’ll continue to extend this and clean up naming and class hierarchy. I’ve also decided on making some videos that I’ll put up on YouTube, which wich will include stuff about C++. Might even try to go Rust for WASM, just because it is possible, and will improve code safety. We’ll see.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s