• 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.

MSFS Need help with SimVars in MFS2020

Messages
4
Hello.

I've been developing software that needs to track the plane data from the sim, and I've been having some issues getting the correct values for the SimVars from the sim. My program is in C++ (though I mainly do C-styled coding because it's all I really know. I haven't been able to find time to learn the modern C++ styles) so I've been going through old FSX/P3D examples/samples to try and work out why my program won't work properly, but I'm completely stumped now.

It first started making me frustrated when I tried to access the SimVar BRAKE PARKING INDICATOR, and it not giving me the same type of values as when I had SIM ON GROUND set up the exact same way. So even though they were set up the same way, and the data was exactly the same type, the On Ground bool always works, and the parking brake indicator never does lol. To try and combat this (because I'm trying to write in flight states for the plane, and yes I know that AI Traffic states exist, I just want manual ones set up by conditional statements), I just wrote in some ground velocity things because that WAS working, and now after removing the parking brake indicator, that SimVar doesn't work anymore either.

Here's the cpp file for the simconnect stuff: (the one I'm currently using is the singlePos() function)
C++:
#include "cSimConnect.h"




void cSimConnect::trackPos()
{
    quit = 0;
    
    HRESULT hr;

    if (SUCCEEDED(SimConnect_Open(&hSimConnect, "Request Data", nullptr, 0, nullptr, 0)))
    {
        printf("\nConnected to MFS!");

        // Set up the data definition, but do not yet do anything with it
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "title", nullptr, SIMCONNECT_DATATYPE_STRING256);
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Kohlsman setting hg", "inHg");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Plane Altitude", "feet");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Plane Latitude", "degrees");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Plane Longitude", "degrees");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "SIM ON GROUND", nullptr, SIMCONNECT_DATATYPE_INT32);

        // Request an event when the simulation starts
        hr = SimConnect_SubscribeToSystemEvent(hSimConnect, EVENT_SIM_START, "SimStart");
        /*hr = SimConnect_SubscribeToSystemEvent(hSimConnect, KEY_PARKING_BRAKES, "PARKING_BRAKES");*/ // Doesn't work because not a system event apparently

        hr = SimConnect_MapClientEventToSimEvent(hSimConnect, KEY_PARKING_BRAKES, "PARKING_BRAKES"); // Sets an event for the parking brakes to be toggled (processed in process).
        hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUP0, KEY_PARKING_BRAKES);
        hr = SimConnect_SetNotificationGroupPriority(hSimConnect, GROUP0, SIMCONNECT_GROUP_PRIORITY_HIGHEST);

        hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_1, DEFINITION_1, SIMCONNECT_OBJECT_ID_USER,
            SIMCONNECT_PERIOD_SECOND, 0, 0, 1, 0); // Get the info from the game every second (for now, might want to change it later like having it check once for airport and use this for flight tracking).

//         hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_1, DEFINITION_1, SIMCONNECT_OBJECT_ID_USER,
//             SIMCONNECT_PERIOD_ONCE, 0, 0, 0, 0); // Get plane info once

        while (0 == quit)
        {
            SimConnect_CallDispatch(hSimConnect, DispatchCallback, this);
            Sleep(1);
        }

        hr = SimConnect_Close(hSimConnect);
    }
}

void cSimConnect::DispatchCallback(SIMCONNECT_RECV* pData, DWORD cbData, void* pContext)
{
    cSimConnect* pThis = reinterpret_cast<cSimConnect*>(pContext);
    pThis->Process(pData, cbData);
}

void cSimConnect::Process(SIMCONNECT_RECV* pData, DWORD cbData)
{
    HRESULT hr;

    printf("\nProcess was called");
    /*hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_1, DEFINITION_1, SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD_SECOND);*/

    switch (pData->dwID)
    {
            case SIMCONNECT_RECV_ID_EVENT:  // I can use this case for binding to parking brake for job completion if we want (though the code would have to change).
            {
                SIMCONNECT_RECV_EVENT* evt = (SIMCONNECT_RECV_EVENT*)pData;
    
                switch (evt->uEventID)
                     {
                    case EVENT_SIM_START:
            
                         // Now the sim is running, request information on the user aircraft
                        /*hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_1, DEFINITION_1, SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD_SECOND);*/
//                         hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_1, DEFINITION_1, SIMCONNECT_OBJECT_ID_USER,
//                             SIMCONNECT_PERIOD_SECOND, 0, 0, 1, 0);
                         break;
                    case KEY_PARKING_BRAKES:
                        printf("\nThe Parking Brakes were toggled\n");
                        quit = 1;
                        break;
                    }
                 break;
             }

    case SIMCONNECT_RECV_ID_SIMOBJECT_DATA:
    {
        SIMCONNECT_RECV_SIMOBJECT_DATA* pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA*)pData;

        printf("\nObject data received\n");

        switch (pObjData->dwRequestID)
        {
        case REQUEST_1:
        {
            DWORD ObjectID = pObjData->dwObjectID;
            dataStruct* pS = (dataStruct*)&pObjData->dwData;
            if (SUCCEEDED(StringCbLengthA(&pS->title[0], sizeof(pS->title), nullptr))) // security check
            {
                printf("\nObjectID=%d  title=\"%s\"\nLat=%f  Lon=%f  Alt=%f  Kohlsman=%.2f\n", ObjectID, pS->title, pS->latitude, pS->longitude, pS->altitude, pS->kohlsmann);
            }
            break;
        }

        default:
            break;
        }
        break;
    }


    case SIMCONNECT_RECV_ID_QUIT:
    {
        quit = 1;
        break;
    }

    default:
        printf("\nReceived:%d", pData->dwID);
        break;
    }
}

void cSimConnect::singlePos()
{
    quit = 0;

    HRESULT hr;

    if (SUCCEEDED(SimConnect_Open(&hSimConnect, "Request Data", nullptr, 0, nullptr, 0)))
    {
        /*printf("\nConnected to MFS!");*/

        // Set up the data definition, but do not yet do anything with it
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "title", nullptr, SIMCONNECT_DATATYPE_STRING256);
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Kohlsman setting hg", "inHg");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Plane Altitude", "feet");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Plane Latitude", "degrees");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Plane Longitude", "degrees");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "SIM ON GROUND", nullptr, SIMCONNECT_DATATYPE_INT32);
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "GROUND VELOCITY", "Knots");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Ground Altitude", "Feet");

        // Request an event when the simulation starts
        hr = SimConnect_SubscribeToSystemEvent(hSimConnect, EVENT_SIM_START, "SimStart");
        /*hr = SimConnect_SubscribeToSystemEvent(hSimConnect, KEY_PARKING_BRAKES, "PARKING_BRAKES");*/ // Doesn't work because not a system event apparently

//         hr = SimConnect_MapClientEventToSimEvent(hSimConnect, KEY_PARKING_BRAKES, "PARKING_BRAKES"); // Sets an event for the parking brakes to be toggled (processed in process).
//         hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUP0, KEY_PARKING_BRAKES);
//         hr = SimConnect_SetNotificationGroupPriority(hSimConnect, GROUP0, SIMCONNECT_GROUP_PRIORITY_HIGHEST);

        //         hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_1, DEFINITION_1, SIMCONNECT_OBJECT_ID_USER,
        //             SIMCONNECT_PERIOD_SECOND, 0, 0, 1, 0); // Get the info from the game every second (for now, might want to change it later like having it check once for airport and use this for flight tracking).

        hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_1, DEFINITION_1, SIMCONNECT_OBJECT_ID_USER,
            SIMCONNECT_PERIOD_ONCE); // Get plane info once

        while (0 == quit)
        {
            SimConnect_CallDispatch(hSimConnect, DispatchCallbackSingle, this);
            Sleep(1);
        }

        hr = SimConnect_Close(hSimConnect);
    }
}

void cSimConnect::DispatchCallbackSingle(SIMCONNECT_RECV* pData, DWORD cbData, void* pContext)
{
    cSimConnect* pThis = reinterpret_cast<cSimConnect*>(pContext);
    pThis->ProcessSingle(pData, cbData);
}

void cSimConnect::ProcessSingle(SIMCONNECT_RECV* pData, DWORD cbData)
{
    HRESULT hr;

    /*printf("\nProcess was called");*/
    /*hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_1, DEFINITION_1, SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD_SECOND);*/

    switch (pData->dwID)
    {
    case SIMCONNECT_RECV_ID_EVENT:  // I can use this case for binding to parking brake for job completion if we want (though the code would have to change).
    {
        SIMCONNECT_RECV_EVENT* evt = (SIMCONNECT_RECV_EVENT*)pData;

        switch (evt->uEventID)
        {
        case EVENT_SIM_START:

            // Now the sim is running, request information on the user aircraft
            /*hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_1, DEFINITION_1, SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD_SECOND);*/
//                         hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_1, DEFINITION_1, SIMCONNECT_OBJECT_ID_USER,
//                             SIMCONNECT_PERIOD_SECOND, 0, 0, 1, 0);
            break;
        case KEY_PARKING_BRAKES:
            /*printf("\nThe Parking Brakes were toggled\n");*/
            quit = 1;
            break;
        }
        break;
    }

    case SIMCONNECT_RECV_ID_SIMOBJECT_DATA:
    {
        SIMCONNECT_RECV_SIMOBJECT_DATA* pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA*)pData;

        /*printf("\nObject data received\n");*/

        switch (pObjData->dwRequestID)
        {
        case REQUEST_1:
        {
            DWORD ObjectID = pObjData->dwObjectID;
            dataStruct* pS = (dataStruct*)&pObjData->dwData;
            if (SUCCEEDED(StringCbLengthA(&pS->title[0], sizeof(pS->title), nullptr))) // security check
            {
                /*printf("\nObjectID=%d  title=\"%s\"\nLat=%f  Lon=%f  Alt=%f  Kohlsman=%.2f\n", ObjectID, pS->title, pS->latitude, pS->longitude, pS->altitude, pS->kohlsmann);*/
                latitude = pS->latitude;
                longitude = pS->longitude;
                onGround = pS->onGround;
                title = pS->title;
                altitude = pS->altitude;
                groundVelocity = (pS->gvel);
                groundAlt = pS->grndalt;
                quit = 1;
            }
            break;
        }

        default:
            break;
        }
        break;
    }


    case SIMCONNECT_RECV_ID_QUIT:
    {
        quit = 1;
        break;
    }

    default:
        /*printf("\nReceived:%d", pData->dwID);*/
        break;
    }
}

And here's the code for the header file:

C++:
#pragma once
#include <Windows.h>
#include <tchar.h>
#include <cstdio>
#include <strsafe.h>
#include <SimConnect.h>
#include <iostream>
#include <string>



static enum GROUP_ID {
    GROUP0,
};

static enum EVENT_ID {
    EVENT_SIM_START,
    KEY_PARKING_BRAKES,
};

static enum DATA_DEFINE_ID {
    DEFINITION_1,
};

static enum DATA_REQUEST_ID {
    REQUEST_1,
};

struct dataStruct
{
    char    title[256];
    double  kohlsmann;
    double  altitude;
    double  latitude;
    double  longitude;
    bool onGround;
    double gvel;
    double grndalt;
};

class cSimConnect
{
public:
    std::string title;
    double  kohlsmann;
    double  altitude;
    double  latitude;
    double  longitude;
    bool onGround;
    double groundVelocity;
    double groundAlt;

    HANDLE hSimConnect; // use SimConnect_Open to set this value.
    int quit;

    void trackPos();
    static void DispatchCallback(SIMCONNECT_RECV* pData, DWORD cbData, void* pContext);
    void Process(SIMCONNECT_RECV* pData, DWORD cbData);
    void singlePos();
    static void DispatchCallbackSingle(SIMCONNECT_RECV* pData, DWORD cbData, void* pContext);
    void ProcessSingle(SIMCONNECT_RECV* pData, DWORD cbData);
};

I'd like to know how to be able to fix this code so that it properly gives me correct data from the sim for all the different SimVar's that I might need (eventually need heading indication and guage info as well if it's possible, as well as payload and fuel info which also need to be settable if that's at all possible in MFS2020). I'm coming here as a last resort, so please give me any advice you can, thanks.

Sidenote: I'm not the greatest at C++ and I'm still learning quite a bit each day, but I should know enough to be able to understand your responses, though if you could make sure to link stuff to sources that explain anything more complicated I'd really appreciate it.
 
I don't understand why you have trackPos and singlePos and why you are adding the same events to the same DEFINITION_1 in each.

I'd also change:

hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "SIM ON GROUND", nullptr, SIMCONNECT_DATATYPE_INT32);

to

hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "SIM ON GROUND", "bool", SIMCONNECT_DATATYPE_FLOAT64);

If you want to be notified when the key_parking_brakes event happens (usually through user input) use:

if ( SUCCEEDED(hr) ) hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_MAGNETO_OFF, "MAGNETO_OFF");

then

if ( SUCCEEDED(hr) ) hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUPB, EVENT_MAGNETO_OFF, TRUE);

The true will not pass this event to the sim. Set to FALSE if you just want to be notified.

you can then add a

case EVENT_MAGNETO_OFF

in your Process to handle the event.
 
They're different in terms of one could be on a separate thread constantly updating things and one is used for single position checks.

The key_parking_brakes event was from an old thing that I was testing to end the trackingpos function early without having to exit the sim, and not really to check if the parking brake was enabled.

I was using hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "BRAKE PARKING INDICATOR", "bool", SIMCONNECT_DATATYPE_INT32); for the parking brake indication simvar, but it wasn't working. I read that you were supposed to use the int32 for the bools in the documentation, and not the standard float64.

Any thoughts on why I'm not getting the correct data from the sim though? I was hoping I could get some insight as to why the ground velocity wasn't returning the correct data from the sim, and why the parking brake indicator doesn't seem to work (sometimes it's true and sometimes it's false, but it's never related to the sim parking brake being on or off. The ground velocity was showing things like -2780000 (not the actual number, but the same magnitude in depth) instead of the 0 or less than 30knots that I was testing at.
 
When I tried what you said with changing it to a float64 it broke it even more, so I don't think that's the thing to do.
 
I haven't done MSFS but in FSX you could just use float64 for everything because everything was really float64, even so called bool. I see MSFS simulation variables now lists the type so I guess it matters now. Although, there is no type for brake parking indicator. I'd try another variable and match the type and ensure that your variable type in your struct is large enough to hold it.

Also looking at the struct code you have:

dataStruct* pS = (dataStruct*)&pObjData->dwData;

I have

Struct_7 *pS = (Struct_7*)&pObjData->dwData;

I think the location of the asterisk could be a major issue.
 
On a side note... how'd we get put at the bottom of the list? LOL
This was the only place that I could find that was having discussions on simconnect, so my "last resort" is asking a question. My first things that I do when I run into a problem is to read a bunch of articles and other forum threads to try and figure out a solution that can work, and then finish it off if none of that works by asking a question in a forum that discusses the topic I'm struggling with lol. Didn't mean that this was a bad place or anything.
Only if they've changed the C/C++ coding convention.
You can have it on either the end of the class or beginning of the variable/object. I use visualAssist and they just keep defaulting it to placing it behind the class identifier even if I put it on the object pointer. It's working both ways that I tried it, so I don't think it actually matters.

I think I've gotten it working somehow though (haven't tried the parking brake indicator again, but all the rest of the variables I need are working as intended now). What helped was rearranging the order of the variables, and splitting them up into multple requests/definitions. The Sim On Ground bool was messing up all the following variables after it, so by moving it to the bottom of the list all of it worked. Maybe someone can explain why this is. I have a feeling it's due to the memory addresses being improperly accessed which caused some overflow/offset issues that made the entries in memory not be what the sim intended.
 
You were passing nullptr instead of a unit string. I would think that would cause problems. Also, unless they've done a complete rewrite of SimConnect... expect all return values to be of type FLOAT64 for memory sizing.
 
Have you solved your problem or do you still need help?
 
Last edited:
Back
Top