Sign in to follow this  
dragonflightdesign

SimConnect inside a gauge - not connecting

Recommended Posts

I'm hoping someone can point out the obvious for me - apart from the fact that I've unashamedly stolen some of Doug Dowson's code ideas! :lol: The problem is that the code never steps into the Dispatch callback. From debugging I know that the code is stepping into the PANEL_SERVICE_PRE_UPDATE but that's it - it just steps right out again.

 

 

#include "simconnect.h"
#include "SimConnectProcs.cpp"

char simconnect_data_gauge_name[] = GAUGE_NAME;
extern PELEMENT_HEADER        simconnect_data_list;
GAUGE_CALLBACK simconnect_data_update;
GAUGE_HEADER_FS900(gaugehdr_simconnect_data,GAUGE_W, simconnect_data_gauge_name, &simconnect_data_list, 0, simconnect_data_update, 0,0);

MAKE_STATIC (simconnect_data_background_static,
                        DYNBG,
                        NULL,
                        NULL,
                        erase | transparent,
                        0,
                        0,0 )

PELEMENT_HEADER    simconnect_data_list    = &simconnect_data_background_static.header;

//---------------------------------------------------------------------------
// Dispatch callback
//---------------------------------------------------------------------------
void CALLBACK SimConnectProcess(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext)
{

    switch (pData->dwID)
    {
        case SIMCONNECT_RECV_ID_OPEN: //2
            OnRecvOpen((SIMCONNECT_RECV_OPEN*)pData, cbData);
        break;

    case SIMCONNECT_RECV_ID_EVENT: //4
        OnRecvEvent((SIMCONNECT_RECV_EVENT*)pData, cbData);
        break;

    case SIMCONNECT_RECV_ID_EVENT_FILENAME: // 6
        OnRecvEventFilename((SIMCONNECT_RECV_EVENT_FILENAME*)pData, cbData);
        break;

    case SIMCONNECT_RECV_ID_EVENT_FRAME: //7
        OnRecvSimObjectFrame((SIMCONNECT_RECV_EVENT_FRAME*)pData, cbData);
        break;

    case SIMCONNECT_RECV_ID_SIMOBJECT_DATA: //8
        OnRecvSimobjectData((SIMCONNECT_RECV_SIMOBJECT_DATA*)pData, cbData);
        break;

    case SIMCONNECT_RECV_ID_SIMOBJECT_DATA_BYTYPE: //9
        OnRecvSimobjectDataByType((SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE*)pData, cbData);
        break;

    case SIMCONNECT_RECV_ID_WEATHER_OBSERVATION: //10
        OnRecvWeatherObservation((SIMCONNECT_RECV_WEATHER_OBSERVATION*)pData);
        break;

    case SIMCONNECT_RECV_ID_EXCEPTION: //1
        OnRecvException((SIMCONNECT_RECV_EXCEPTION*)pData, cbData);
        break;
    }
}

//---------------------------------------------------------------------------
// Gauge callback
//---------------------------------------------------------------------------
void FSAPI simconnect_data_update(PGAUGEHDR pgauge, int service_id, UINT32 extra_data)
{
    switch (service_id)
    {

        case    PANEL_SERVICE_PRE_UPDATE:
            SimConnect_CallDispatch(hSimConnect, SimConnectProcess, NULL);
        break;

        case    PANEL_SERVICE_PRE_KILL:
            hr = SimConnect_Close(hSimConnect);
        break;

    }
}

Share this post


Link to post
Share on other sites
Help AVSIM continue to serve you!
Please donate today!

I think you need to subscribe first to the wished SimConnect services you need, before SimConnect actually calls your callback function.

 

I don't have my dev computer here, but I'll be able tonight to give you the correct sample (but I'm quite sure someone will bring it to you before :) )

Share this post


Link to post
Share on other sites

Roland is correct. You haven't asked to be notified of anything, thus there's nothing to call about.

Share this post


Link to post
Share on other sites

Ah right... missed this:

 

 

case        PANEL_SERVICE_CONNECT_TO_WINDOW:
    SimConnect_Open(&hSimConnect, GAUGE_NAME, NULL, 0, NULL, SIMCONNECT_OPEN_CONFIGINDEX_LOCAL);
    break;

 

but of course, it's led to another problem. This is killing my screen update rate to about one frame every forty seconds (framerate still claims to be in the 32fps region but I don't believe it). Currently all it's doing is retrieving the current flight name.

 

case    PANEL_SERVICE_PRE_UPDATE:
        SimConnect_CallDispatch(hSimConnect, SimConnectProcess, NULL);
    break;

 

I'm really struggling with SimConnect. Doug was kind enough to give me his dsd_battery_charger code but he's used the 'bare' gauge code from the fsxgauges_sp2.h file rather than the gauge macros supplied by ACES. His connect and disconnect code is in the module_init and _deinit functions; if I try to use them in similar fashion I get a shedload of compile errors complaining about duplication (as expected). The examples supplied with the FSX SDK all use an external .exe connecting to FS, so I haven't been able to get much help from there. My end aim is to effectively create a SimConnect 'framework' that can be attached to any future project rather than create custom SimConnect code for each new project.

Share this post


Link to post
Share on other sites

Well, then all of your SimConnect code needs to reside outside of the gauge.

Share this post


Link to post
Share on other sites

That was quick Ed! Much as I agree with your method of making people think (and as this is written media, I am not being sarcastic), sometimes a wee bit more detail would be a help.

 

Yes, I understand your comment about creating the SimConnect code outside the main project gauge and I'm (now) obviously going to have to use that route. Doug's code does that, so I know I can use it as a guide. Unfortunately, that leads me right round to where I started. I can get the loaded flight in the 'SimConnect gauge' but as this is/will be an external dll, how do I pass that information to the panel gauge? There are many examples in the SDK of using external events to influence internal event_ids but nothing on how to pass in e.g. EVENT_FILENAME data. That is where I need chapter-and-verse hand-holding!

Share this post


Link to post
Share on other sites

Ok... I apologize... I've been ill and clearly my mind isn't functional yet. *sigh*

 

Give me a few minutes and I'll try to post something of value.

 

Maybe of value:

 

First, you appear to be trying to use the polling method. That's going to be a performance hit. You should use an event driven interface that allows SimConnect to call your dispatch routine only when necessary.

 

Second, you've still not actually told SimConnect to provide you with anything (unless you're intentionally not showing that here??). Without that, there's nothing to really do at all.

 

I create my SimConnect interface in the module_init phase when the gauge DLL is first loaded (this can be a dll_init routine instead). I use the event callback method instead of polling.

 

I initialize my SimConnect in the PANEL_SERVICE_PRE_INSTALL service loop. In that initialization I open SimConnect, I map all events and data I am interested in

Share this post


Link to post
Share on other sites

Dai,

 

You should be able to move the stuff I have in module_init and module_deinit to PANEL_SERVICE_CONNECT_TO_WINDOW and PANEL_SERVICE_DISCONNECT.

I don't use PANEL_SERVICE_PRE_INSTALL for initialization stuff because it gets called when the panel window is resized or moved.

 

When you are running SimConnect in a gauge, you only need to call SimConnect_CallDispatch once.  It registers your callback function and that function gets called as needed.  Don't call SimConnect_CallDispatch on each frame or update.

 

I use the SIMCONNECT_RECV_ID_OPEN case in the callback function to set up all the information I want to sent to or receive from SimConnect.

Share this post


Link to post
Share on other sites

I have seen crashes when relying on the PANEL_SERVICE_CONNECT_TO_WINDOW and PANEL_SERVICE_DISCONNECT service ID's so I avoid them when possible. If one were to properly mark that they initialized SimConnect in the PRE_UPDATE (say with a bool var that gets set to true)... it doesn't matter how many times PRE_UPDATE gets called. The bool marker is a good coding practice anyway. :wink:

Share this post


Link to post
Share on other sites

Ed: no, I wasn't deliberately keeping the rest of my code hidden. In fact, the only reason I saw your reply so quickly was because I'd logged back in to add it. Just for completeness, here it is:

 

static enum EVENT_FILENAME
{
        EVENT_FLIGHT_LOAD,
};

void OnRecvOpen (SIMCONNECT_RECV_OPEN *pOpen, DWORD cbData)
{
// System events
    hr = SimConnect_Open(&hSimConnect, "System Event", NULL, 0, 0, 0);
    if (SUCCEEDED(hr)) 
    {
        hr = SimConnect_SubscribeToSystemEvent(hSimConnect, EVENT_FLIGHT_LOAD, "FlightLoaded");
    }
}
 
void OnRecvEventFilename(SIMCONNECT_RECV_EVENT_FILENAME *pData, DWORD cbData)
{
    strncpy(CURRENT_FLIGHT,pData->szFileName,sizeof(pData->szFileName));
}

 

Doug: I'm still not sure how you are calling/listening to the SimConnect code but I want a bit more time to try and figure it out before asking again. If I get the 'lightbulb moment' then it's more likely to stick. Whatever way the enlightenment comes, I will be writing up for a new version of sd2gau.

Share this post


Link to post
Share on other sites

I'm a wee bit confused now. Why are you calling SimConnect_Open in a function titled OnRecvOpen (called from where??) and yet you also have a call to SimConnect_Open in your PANEL_SERVICE_CONNECT_TO_WINDOW service code?

Share this post


Link to post
Share on other sites

I now know that code is all wrong. I'm a bit ahead of that now; I'm hitting "exception=7" but as that appears to be a naming problem (incorrect info in one or more SDK files?) I should be able to solve that one. If the whole lot really goes Pete Tong and I can't solve it with yours and Doug's (and anyone else's) help, I'll post all the code somewhere. It's not secret or complex.


But if anyone's feeling generous, here's the faulty line

 

if(SUCCEEDED(hr))SimConnect_AddToDataDefinition(hSimConnect, EVENT_FLIGHT_LOAD, "FlightLoaded", NULL, SIMCONNECT_DATATYPE_STRING256, 0);

I can't look at this again now until tomorrow - work calls :mad:

Share this post


Link to post
Share on other sites

FlightLoaded isn't a valid variable.

 

If you want to know when a flight has been loaded and what the .FLT file name is... SimConnect_RequestSystemState is the function you need to use.

 

If you want to 'listen' for the flight load... you use SimConnect_SubscribeToSystemEvent and pass it "FlightLoaded" as the event ID.

Share this post


Link to post
Share on other sites

You knew I'd be back, didn't you? :smile:

 

For the SimConnect_CallDispatch method the FSX SDK (and the Prepare3D SDK) both give the following example:

 

int quit = 0;
....
//
while( quit == 0 )
{
  hr = SimConnect_CallDispatch(hSimConnect, MyDispatchProc, NULL);
};

 

This implies (and I say 'implies' because I suspect this is my last stumbling block) that the _CallDispatch should be called from PANEL_SERVICE_PRE_UPDATE. Taking both Ed's and Doug's suggestions into account, my current code looks like this:

 

 

//---------------------------------------------------------------------------
// Gauge callback
//---------------------------------------------------------------------------
void FSAPI simconnect_data_update(PGAUGEHDR pgauge, int service_id, UINT32 extra_data)
{
    static bool bSimConnect = false;

    switch (service_id)
    {
    case    PANEL_SERVICE_PRE_UPDATE:

        if (bSimConnect==false)
        {
            hr=SimConnect_Open(&hSimConnect, GAUGE_NAME, NULL, 0, NULL, SIMCONNECT_OPEN_CONFIGINDEX_LOCAL);
            bSimConnect = true;
        }

        if (bSimConnect == true)
        {
            hr=SimConnect_CallDispatch(hSimConnect, SimConnectProcess, NULL);
        }

        break;

    case    PANEL_SERVICE_DISCONNECT:
            hr=SimConnect_Close(hSimConnect);
        break;

    }
}


//---------------------------------------------------------------------------
// Dispatch callback
//---------------------------------------------------------------------------
void CALLBACK SimConnectProcess(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext)
{
    switch (pData->dwID)
    {
        case SIMCONNECT_RECV_ID_OPEN: //2
            OnRecvOpen((SIMCONNECT_RECV_OPEN*)pData, cbData);
        break;

    case SIMCONNECT_RECV_ID_EVENT: //4
        OnRecvEvent((SIMCONNECT_RECV_EVENT*)pData, cbData);
        break;

    case SIMCONNECT_RECV_ID_EVENT_FILENAME: // 6
        OnRecvEventFilename((SIMCONNECT_RECV_EVENT_FILENAME*)pData, cbData);
        break;

    case SIMCONNECT_RECV_ID_EVENT_FRAME: //7
        OnRecvSimObjectFrame((SIMCONNECT_RECV_EVENT_FRAME*)pData, cbData);
        break;

    case SIMCONNECT_RECV_ID_SIMOBJECT_DATA: //8
        OnRecvSimobjectData((SIMCONNECT_RECV_SIMOBJECT_DATA*)pData, cbData);
        break;

    case SIMCONNECT_RECV_ID_SIMOBJECT_DATA_BYTYPE: //9
        OnRecvSimobjectDataByType((SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE*)pData, cbData);
        break;

    case SIMCONNECT_RECV_ID_WEATHER_OBSERVATION: //10
        OnRecvWeatherObservation((SIMCONNECT_RECV_WEATHER_OBSERVATION*)pData);
        break;

    case SIMCONNECT_RECV_ID_EXCEPTION: //1
        OnRecvException((SIMCONNECT_RECV_EXCEPTION*)pData, cbData);
        break;
    }
}

//---------------------------------------------------------------------------
// SimConnectProcs.cpp
//---------------------------------------------------------------------------
HANDLE hSimConnect;
HRESULT hr;

static enum EVENT_FILENAME
{
        EVENT_FLIGHT_LOAD,
};

void OnRecvOpen (SIMCONNECT_RECV_OPEN *pOpen, DWORD cbData)
{
// System events
        SimConnect_SubscribeToSystemEvent(hSimConnect, EVENT_FLIGHT_LOAD, "FlightLoaded");
}
 
void OnRecvEventFilename(SIMCONNECT_RECV_EVENT_FILENAME *pData, DWORD cbData)
{
    strncpy(CURRENT_FLIGHT,pData->szFileName,sizeof(pData->szFileName));
}
 
etc..

 

However, after the first connection where FlightLoaded is registered (viewed in the SimConnect debug dialog), _CallDispatch is never triggered again. Ed said it's event-driven; the SDK implies that you need to listen for an event using the PRE_UPDATE callback.

 

I sound like I know what I'm talking about but I obviously don't. Where am I missing the connection?

Share this post


Link to post
Share on other sites

There's nothing else it needs to do. While you subscribed to the event, at no point in your code are you checking to see if that event came in... and since it should only come in once... that should be it.

 

What were you expecting? Constant callbacks for nothing? (not trying to be facetious)...

Share this post


Link to post
Share on other sites

The FLIGHT_LOADED event is happening before you ever get to PANEL_SERVICE_PRE_UPDATE to initiate your connection to SimConnect.

Share this post


Link to post
Share on other sites

This gets more complex... :Big Grin:

 

Ed: thank you for confirming what I'd suspected was the underlying problem. And no, I didn't think you were being facetious. I just don't yet have the SimConnect modus operandi successfully nailed in my head.

Doug: where do you suggest that I trap 'early' events like this?

 

[Edit] Doug: just as I posted I think I figured it out. I won't be able to try until tomorrow morning, so I'd like to see if I've got it right first.

Share this post


Link to post
Share on other sites

I really thought I'd got it this time with Ed's hint about event driven.

 

case    PANEL_SERVICE_PRE_UPDATE:

    if ((strlen(prevFlight) < 3) || strcmp(prevFlight,CURRENT_FLIGHT)!=0)
    {
        hr = SimConnect_RequestSystemState(hSimConnect, SIMCONNECT_RECV_ID_EVENT_FILENAME, "FlightLoaded");
        SimConnect_CallDispatch(hSimConnect, SimConnectProcess, NULL);
        if (strlen(CURRENT_FLIGHT) > 3)
            strncpy(prevFlight, CURRENT_FLIGHT, sizeof(CURRENT_FLIGHT));
    }
    break;

_CallDispatch still isn't being called but the RequestSystemState is definately going out. I went on and did some further coding/checking and found I could easily trap FlightSaved:

 

static enum EVENT_FILENAME
{
        FLIGHT_LOADED,
        FLIGHT_SAVED,
};

void OnRecvOpen (SIMCONNECT_RECV_OPEN *pOpen, DWORD cbData)
{
        SimConnect_SubscribeToSystemEvent(hSimConnect, FLIGHT_LOADED, "FlightLoaded");
        SimConnect_SubscribeToSystemEvent(hSimConnect, FLIGHT_SAVED, "FlightSaved");
}

void OnRecvEventFilename(SIMCONNECT_RECV_EVENT_FILENAME *pData, DWORD cbData)
{
    if (FLIGHT_SAVED)strncpy(SAVED_FLIGHT,pData->szFileName,sizeof(pData->szFileName));
    if (FLIGHT_LOADED)strncpy(CURRENT_FLIGHT, pData->szFileName, sizeof(pData->szFileName));
}

What am I not calling correctly for FlightLoaded? And with apologies, because I'm right at the end of my tether with frustration, may I ask if someone would be kind enough to provide some code? I obviously can't take hints.

Share this post


Link to post
Share on other sites

Dai,

 

Call SimConnect_CallDispatch once, as soon as you call SimConnect_Open.

When you are  running in process (a gauge or module) you do not have to continually call it.

Share this post


Link to post
Share on other sites

That's what I was doing when I found that I could successfully read FlightSaved - the above code was my last despairing try before I went to bed last night. Now I'm seriously beginning to wonder if FlightLoaded actually works.

Share this post


Link to post
Share on other sites

Sorry, I just noticed this.  I think you want

void OnRecvEventFilename(SIMCONNECT_RECV_EVENT_FILENAME *pData, DWORD cbData)
{
    if (pData->uEventID == FLIGHT_SAVED)strncpy(SAVED_FLIGHT,pData->szFileName,sizeof(pData->szFileName));
    if (pData->uEventID == FLIGHT_LOADED)strncpy(CURRENT_FLIGHT, pData->szFileName, sizeof(pData->szFileName));
}

Share this post


Link to post
Share on other sites

I did some testing myself.  I'm now pretty certain that the "FlightLoaded" event occurs before gauges start getting loaded, so we'll never trap it in a gauge.

If you need to know the current flight name, use the SimConnect_RequestSystemState function.

Share this post


Link to post
Share on other sites

Thanks Doug - I was starting to think I was being particularly stupid. If I don't get it tonight, it will have to wait until I get back from Florida in ten days' time.

Share this post


Link to post
Share on other sites

:yahoo: AT LAST!!! That has been one steep learning curve - ! It was like someone turned a (dim) light on sometime over the last two days and I'm now starting to understand the SDK.

 

Thank you both very much for your help :BigGrin::drinks: 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this