5. Reading SimVar data with SimConnect SDK
Prerequisites for Developing with the MSFS SDK
Before we start developing with the MSFS SDK, there are a few things you’ll need to have installed:
- Microsoft Flight Simulator 2020: Ensure you have a copy of MSFS 2020 installed on your machine.
- Enable Developer Mode: While not strictly necessary for using the SDK, enabling Developer Mode within the simulator is recommended. This mode allows you to download the SDK directly from within the sim and provides access to additional tools that will be useful throughout the development process, which I’ll cover below.
Note: when you install the SDK it goes under your C:\MSFS SDK
folder, so keep that in mind if you install it elsewhere.
- Microsoft Visual Studio 2022. You can download the free Community version here. During installation, make sure to select the .NET desktop development workload, as this will include everything you need to develop WPF applications. Once installed, you’re ready to move on to the next step.
Setting up your project
Lets proceed by creating a new project. A .NET WPF Application is ideal for what I want to achieve. However, if you prefer, you can write a Console Application and most of the steps this tutorial still applies.
After completing the "Create New Project" wizard in Visual Studio, the first thing you should do is configure your project file. To do this:
- In the Solution Explorer, right-click on your project’s name.
- Select Edit Project File.
This allows you to manually adjust the project settings, add dependencies, and make other configurations necessary for integrating the MSFS SDK.
- To properly integrate the MSFS SDK, you need to reference the SimConnect library in your project. Add the following two
<ItemGroup>
entries in lines 12 through 24 to your project file to includeSimConnect.dll
for both build and runtime:
Note: If you installed the SDK in a different location, update these paths accordingly.
Build an Altimeter... kinda...
Let’s start by building a simple instrument: the Altimeter. For this, we need to read two values from the simulator: the indicated altitude and the barometric pressure setting. By consulting the Simulation Variables documentation, we can identify the specific SimVars that will provide these values:
SimVar | Descritpion | Units |
---|---|---|
INDICATED ALTITUDE | The indicated altitude. | feet |
KOHLSMAN SETTING HG | The value for the given altimeter index in inches of mercury. | Inches of Mercury, inHg |
Now, let’s build a simple UI for our Altimeter. Open MainWindow.xaml
and add the following XAML code to create a basic layout for displaying the altitude and barometric pressure:
This should create a simple text based altimeter like this:
Implementing the SimConnect Code
With the UI in place, it’s time to add the functionality. Open MainWindow.xaml.cs
and include the following C# code to connect to the simulator and update the UI with the Altimeter data:
Ok that looks like a lot, I swear I tried to keep it as simple as possible, but here is what the code is doing:
- Creating a
SimConnect
object that will be used to read data from the sim - Register the event handlers for when the
SimConnect
object sends the events we are interested on:- OnRecvOpen - handler for when we connect successfully to the sim
- OnRecvQuit - handler for when the sim is exiting
- OnRecvSimobjectData - handler for when the sim sends us a new data object with
SimVars
- OnRecvException - handler for when there is an exception
- Create one or more
structures
that will hold ourSimVars
, which the sim will return with the current values - Create an
enum
with values representing our differentstructures
- Register our two
SimVars
so they can be returned as ourstructure
object. - Use a
DispatcherTimer
to run a background task to check for new data - Connect/Disconnect to/from a local MSFS 2020 instance
- On new data received, update the UI with the latest altimeter values
About Data Types
An important thing we need to keep in mind when designing your struct
is what data types to use. Let's look at our struct:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
private struct SimVars
{
public float Altitude;
public float KohlsmanSettingHg;
}
Notice that in the Simconnect_OnRecvSimobjectData
handler, we are doing an explicit casting of an object
to our SimVars
structure,
simvars = (SimVars)data.dwData[0]
and by doing so, the data gets copied from the object heap into our structure sequentially. This works because of the StructLayout(LayoutKind.Sequential)
attribute we added to our struct, since the structure is stored in memory sequentially as well.
We told SimConnect
the order and how big that data is when we registered the SimVars
via the simconnect.AddToDataDefinition(...)
calls, and specifying the SIMCONENCT_DATATYPE
.
simconnect.AddToDataDefinition(RequestType.PerFrameData, "INDICATED ALTITUDE", "feet", SIMCONNECT_DATATYPE.FLOAT32, 0, SimConnect.SIMCONNECT_UNUSED);
simconnect.AddToDataDefinition(RequestType.PerFrameData, "KOHLSMAN SETTING HG", "inHG", SIMCONNECT_DATATYPE.FLOAT32, 0, SimConnect.SIMCONNECT_UNUSED);
That is, we are expecting to receive 4 bytes for the altitude
and 4 bytes for the barometer
in that order. This exactly matches our SimVars
structure.
This sounds tedious and prone for errors, especially if you add/remove or move the properties in your structure and forget to do the corresponding update where you are registering your SimVars
, so be mindful when updating your struct
.
Here are some of the mappings I've used in my projects:
C# type | SIMCONNECT_DATATYPE |
---|---|
bool, int | INT32 |
long | INT64 |
float | FLOAT32 |
double | FLOAT64 |
string | STRING8, STRING32, STRING64, STRING128, STRING256 |
Note: when you are working withstrings
, you must add an extra annotation specifying the size of thestring
matching theSIMCONNECT_DATATYPE
you registered with
public struct GPS {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string GpsWpNextId; // GPS WP NEXT ID
}
public void RegisterMySimVars()
{
simconnect.AddToDataDefinition(RequestType.PerFrameData, "GPS WP NEXT ID", "", SIMCONNECT_DATATYPE.STRING256, 0, SimConnect.SIMCONNECT_UNUSED);
...
}
Running and Connecting to the Sim
- Start MSFS 2020:Open Microsoft Flight Simulator 2020.Navigate to the World Map.Select your favorite airport and click Fly.Wait for the simulator to finish loading.
- Debugging the App:In Visual Studio, start debugging your application.Once the app is running, click Connect.
- Verify Functionality:If everything is set up correctly, the app should connect to the simulator.You’ll see the Altimeter and Barometer values updating in real-time on your UI.You can interact with the simulator: fly around, adjust the barometer knob, and observe the changes reflected in your application.Since we added some
Debug.WriteLine(...)
statements, we can open the Output View in Visual Studio to see some output. Should look something like this:
Developer Mode
If you haven't already done so, go to General Options-> Developers and turn on DEVELOPER MODE. Save and go back to the sim.
If we go to the top of the screen, you'll see the Developer menu shown. If it's not shown, move your mouse to the top of the screen and it should be visible. It has an autohide option, which you can turn off if you want. Click on the Tools tab and, on the SimConnect Inspector menu item.
Once the SimConnect Inspector window opens, click on the drop down menu and you'll see our new Hello MSFS
application connected to the game.
Fun fact: if you are using other plugins or peripherals that use a plugin like Logitech's Instrument Panel, you'll see them here too.
If we click on the Frames tab, we can see the frame where we registered our two SimVars
and requested data sent to us.
We can also click on the Data Definitions tab and see our two SimVars
:
Fun fact: if you select the other plugins, you can see what SimVars
they have registered, which helps you figure out what to use for yours.
Wrapping things up
This tutorial has covered how to read data from Microsoft Flight Simulator 2020 using the SimConnect SDK. To summarize:
- Reading Data:
- Consult the documentation to find the SimVars you need.
- Add the
SimVars
to yourstruct
and register them usingAddToDataDefinition(...)
.
- Data Order and Type Matching:
- The order in which you register SimVars with
AddToDataDefinition(...)
must match the order of the properties in your data structure. This is crucial for accurate data retrieval. - Ensure that the data types of your structure properties align with the types specified in the SimConnect documentation to avoid mismatches.
- The order in which you register SimVars with