Problem with 'SimConnect_SetDataOnSimObject'

DragonflightDesign

Resource contributor
#1
It's a fuel transfer function. Originally I drove Doug Dowson batty with this one via email - sorry Doug; there was a lot wrong with it which wasn't immediately obvious. I put it down and came back to it after a few months and fixed the calculation problems today. The transfer calculations now all work perfectly; the from_tank has its total reduced and the to_tank has its total increased, but the act of calling SimConnect_SetDataOnSimObject is doing nothing, despite HRESULT returning S_OK.

The data definitions:
Code:
enum DATA_DEFINITION_ID {
    DEFINE_FUEL_LEVEL,
};
Code:
SimConnect_AddToDataDefinition(hSimConnect, DEFINE_FUEL_LEVEL, "FUEL TANK LEFT AUX QUANTITY", "Gallons", SIMCONNECT_DATATYPE_FLOAT64);
SimConnect_AddToDataDefinition(hSimConnect, DEFINE_FUEL_LEVEL, "FUEL TANK RIGHT AUX QUANTITY", "Gallons", SIMCONNECT_DATATYPE_FLOAT64);
SimConnect_AddToDataDefinition(hSimConnect, DEFINE_FUEL_LEVEL, "FUEL TANK CENTER QUANTITY", "Gallons", SIMCONNECT_DATATYPE_FLOAT64);
SimConnect_AddToDataDefinition(hSimConnect, DEFINE_FUEL_LEVEL, "FUEL TANK CENTER2 QUANTITY", "Gallons", SIMCONNECT_DATATYPE_FLOAT64);
SimConnect_AddToDataDefinition(hSimConnect, DEFINE_FUEL_LEVEL, "FUEL TANK CENTER3 QUANTITY", "Gallons", SIMCONNECT_DATATYPE_FLOAT64);
SimConnect_AddToDataDefinition(hSimConnect, DEFINE_FUEL_LEVEL, "FUEL TANK EXTERNAL1 QUANTITY", "Gallons", SIMCONNECT_DATATYPE_FLOAT64);
SimConnect_AddToDataDefinition(hSimConnect, DEFINE_FUEL_LEVEL, "FUEL TANK EXTERNAL2 QUANTITY", "Gallons", SIMCONNECT_DATATYPE_FLOAT64);
SimConnect_AddToDataDefinition(hSimConnect, DEFINE_FUEL_LEVEL, "FUEL TANK RIGHT TIP QUANTITY", "Gallons", SIMCONNECT_DATATYPE_FLOAT64);
SimConnect_AddToDataDefinition(hSimConnect, DEFINE_FUEL_LEVEL, "FUEL TANK LEFT TIP QUANTITY", "Gallons", SIMCONNECT_DATATYPE_FLOAT64);
SimConnect_AddToDataDefinition(hSimConnect, DEFINE_FUEL_LEVEL, "FUEL TANK LEFT MAIN QUANTITY", "Gallons", SIMCONNECT_DATATYPE_FLOAT64);
SimConnect_AddToDataDefinition(hSimConnect, DEFINE_FUEL_LEVEL, "FUEL TANK RIGHT MAIN QUANTITY", "Gallons", SIMCONNECT_DATATYPE_FLOAT64);
Event check:
Code:
/ -----------------------------------------------------------------------------------------------------------------
void OnRecvEvent(SIMCONNECT_RECV_EVENT *pEvent, DWORD cbData)
{
    switch (pEvent->uEventID)
    {
        case CLIENT_EVENT_1SEC:
        {
            // -----------------------------------------------------
            // Fuel state
            hr = SimConnect_RequestDataOnSimObjectType(hSimConnect, REQUEST_FUEL_STATE_DATA, DEFINE_FUEL_LEVEL, 0, SIMCONNECT_SIMOBJECT_TYPE_USER);
            // Transfer fuel function if pumps are on (flow_rate is not zero)
            if (flow_rate)pump_fuel(hSimConnect, from_tank, to_tank, flow_rate);
The pump_fuel function (or some relevant chunks anyway):
Code:
void pump_fuel(HANDLE hSimConnect, double fromTank, double toTank, double flowRate)
{
    (lots of calculation and timer code here)

    from_tank_level = from_tank_level - level_change;
    fuel_tanks[(int)from_tank] = from_tank_level;

    // If not a fuel dump, calculate new level for to_tank and write it.
    if (toTank != -1)
    {
        to_tank_level = to_tank_level + level_change;
        fuel_tanks[(int)to_tank] = to_tank_level;
    }
    // Write the data
    hRes=SimConnect_SetDataOnSimObject(hSimConnect, DEFINE_FUEL_LEVEL, SIMCONNECT_SIMOBJECT_TYPE_USER, NULL, 11, sizeof(fuel_tanks), &fuel_tanks);
Screenshot of the tank struct showing that at the
Code:
 fuel_tanks[(int)to_tank] = to_tank_level;
line, tank zero has reduced from 764 to 754 gallons (fuel dump in progress):

tanks.jpg


but
Code:
    // Write the data
    hRes=SimConnect_SetDataOnSimObject(hSimConnect, DEFINE_FUEL_LEVEL, SIMCONNECT_SIMOBJECT_TYPE_USER, NULL, 11, sizeof(fuel_tanks), &fuel_tanks);
never changes the tank level. Can anyone spot the fail please?
 
#3
Your values of 11 and sizeof(fuel_tanks) tells SimConnect you are sending a memory block of data the size of eleven fuel_tank structs!
 

DragonflightDesign

Resource contributor
#4
I've tried 11, zero and NULL in that parameter (11 was the last one I tried) and none of them worked. At that point sizeof(fuel_tanks) and &fuel_tanks seem to be containing the correct data as shown in the screenshot.
 
#5
I made each definition for each tank has specific definition, I don't know if "DEFINE_FUEL_LEVEL" can combine all together.
my code can suck and flooded fuel tank on my Tu-144 project
 

DragonflightDesign

Resource contributor
#6
It should work; the function is derived from Doug's dsd_fsx_fuel_dump gauge and that reads/writes in one block. I did it that way because there are 28 (!!) crossfeed possibilities.

Maryadi: can you post your code please? Is it possible?
 
#7
definition:
C++:
enum DATA_DEFINE_ID
{
    DEF_FL_CTR1,
    DEF_FL_CTR2,
    DEF_FL_CTR3,
    DEF_FL_LM,
    DEF_FL_LA,
    DEF_FL_LT,
    DEF_FL_RM,
    DEF_FL_RA,
    DEF_FL_RT,
};
C++:
    SimConnect_AddToDataDefinition(hs, DEF_FL_CTR1, "FUEL TANK CENTER QUANTITY", "gallons");
    SimConnect_AddToDataDefinition(hs, DEF_FL_CTR2, "FUEL TANK CENTER2 QUANTITY", "gallons");
    SimConnect_AddToDataDefinition(hs, DEF_FL_CTR3, "FUEL TANK CENTER3 QUANTITY", "gallons");
    SimConnect_AddToDataDefinition(hs, DEF_FL_LM, "FUEL TANK LEFT MAIN QUANTITY", "gallons");
    SimConnect_AddToDataDefinition(hs, DEF_FL_LA, "FUEL TANK LEFT AUX QUANTITY", "gallons");
    SimConnect_AddToDataDefinition(hs, DEF_FL_LT, "FUEL TANK LEFT TIP QUANTITY", "gallons");
    SimConnect_AddToDataDefinition(hs, DEF_FL_RM, "FUEL TANK RIGHT MAIN QUANTITY", "gallons");
    SimConnect_AddToDataDefinition(hs, DEF_FL_RA, "FUEL TANK RIGHT AUX QUANTITY", "gallons");
    SimConnect_AddToDataDefinition(hs, DEF_FL_RT, "FUEL TANK RIGHT TIP QUANTITY", "gallons");

C++:
        case SIMCONNECT_RECV_ID_SIMOBJECT_DATA:
            {
                SIMCONNECT_RECV_SIMOBJECT_DATA* pObjd = (SIMCONNECT_RECV_SIMOBJECT_DATA*)pData;
                switch (pObjd->dwRequestID)
                {
                case REQ_FL_TRANS:
                    {
                            SimConnect_SetDataOnSimObject(hSc, DEF_FL_LT, SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(double), &f.tank1_sc);
                            SimConnect_SetDataOnSimObject(hSc, DEF_FL_RT, SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(double), &f.tank2_sc);
                            SimConnect_SetDataOnSimObject(hSc, DEF_FL_LM, SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(double), &f.tank3_sc);
                            SimConnect_SetDataOnSimObject(hSc, DEF_FL_CTR1, SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(double), &f.tank4_sc);
                            SimConnect_SetDataOnSimObject(hSc, DEF_FL_LA, SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(double), &f.tank5L_sc);
                            SimConnect_SetDataOnSimObject(hSc, DEF_FL_RA, SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(double), &f.tank5R_sc);
                            SimConnect_SetDataOnSimObject(hSc, DEF_FL_CTR2, SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(double), &f.tank6_sc);
                            SimConnect_SetDataOnSimObject(hSc, DEF_FL_RM, SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(double), &f.tank7_sc);
                            SimConnect_SetDataOnSimObject(hSc, DEF_FL_CTR3, SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(double), &f.tank8_sc);
                    }
                    break;
                }
            }
            break;
part of function:
C++:
    f.tank1_sc = f.trans1 + f.timer81ainc + f.timer81binc - f.timer14 - f.timer16 - f.timer18;
    f.tank2_sc = f.trans2 + f.timer82inc - f.timer24 - f.timer26 - f.timer28;
    f.tank3_sc = f.trans3 - f.timer34;
    f.tank4_sc = f.trans4 + f.timer14inc + f.timer24inc + f.timer34inc + f.timer5L4inc + f.timer5R4inc + f.timer64inc + f.timer74inc + f.timer84inc;
    f.tank5L_sc = f.trans5L - f.timer5L4;
    f.tank5R_sc = f.trans5R - f.timer5R4;
    f.tank6_sc = f.trans6 + f.timer16inc + f.timer26inc + f.timer86ainc + f.timer86binc - f.timer64 - f.timer68;
    f.tank7_sc = f.trans7 - f.timer74;
    f.tank8_sc = f.trans8 + f.timer18inc + f.timer28inc + f.timer68inc - f.timer81a - f.timer81b - f.timer82 - f.timer84 - f.timer86a - f.timer86b;

you need to look out @JB3DG D2D sample, I start from there.
 
Last edited:

JB3DG

Resource contributor
#9
Spotted your problem. fuel_tanks is defined as an array of doubles, not a struct right? In that case, don’t use &fuel_tanks. Either just remove the & or use &fuel_tanks[0].
 

DragonflightDesign

Resource contributor
#10
Right about the array of doubles, but it didn't fix the problem. Just FYI, this is the entire transfer function. flow_rate is in lbs/hr and tank enumeration is shown below. If we can fix this, I'll put it in the Resources section because by then it will have been a public collaboration, has to be useful to other people and is not exactly s3kr!t code.
Code:
// Transfer fuel is called from CLIENT_EVENT_1SEC
// If to_tank ==-1 then this is a fuel dump
void pump_fuel(HANDLE hSimConnect, double fromTank, double toTank, double flowRate)
{
    double flow_amount = 0;
    double level_change = 0;
    double from_tank_capacity = 0;
    double to_tank_capacity = 0;
    double from_tank_level = 0;
    double to_tank_level = 0;
    double fuel_tanks[11];

    int i = 0;

    HRESULT hRes;

    // Initialise the fuel_tanks array - getFuelXXX is in fuel_and_oil.h
    for (i=0; i <= 10; i++)fuel_tanks[i]=getFuelQuantity(i);

    // Get the tank capacities
    from_tank_capacity = getFuelCapacity(fromTank);
    if(toTank!=-1)to_tank_capacity = getFuelCapacity(toTank);

    // Get the tank levels
    from_tank_level = getFuelQuantity(fromTank);
    if(toTank!=-1)to_tank_level = getFuelQuantity(toTank);

    // Calculate the amount we need to change the tank levels by
    flow_amount = (flow_rate / 3.600) / fuel_weight.var_value.n;
    level_change = flow_amount / 1000;

    // Test test test
    level_change = 10;

    // Calculate new level for from_tank and check lower limit
    from_tank_level = from_tank_level - level_change;
    if (from_tank_level < 0)from_tank_level = 0;
    fuel_tanks[(int)from_tank] = from_tank_level;

    //If necessary, calculate new level for to_tank and check upper limit
    if (toTank != -1)
    {
        to_tank_level = to_tank_level + level_change;
        if (to_tank_level > to_tank_capacity)to_tank_level = to_tank_capacity;
        fuel_tanks[(int)to_tank] = to_tank_level;
    }
    // Write the data
    hRes = SimConnect_SetDataOnSimObject(hSimConnect, DEFINE_FUEL_LEVEL, SIMCONNECT_SIMOBJECT_TYPE_USER, NULL, NULL, sizeof(fuel_tanks), &fuel_tanks[0]);

    // Test test test check new tank level
    from_tank_level = getFuelQuantity(fromTank);

    return;
}
- and just so I don't sow any confusion, here's the getFuelXXX stuff:
Code:
//**************************************************************************
//  Fuel tank enumeration for fuel use and transfer
//**************************************************************************
enum TANK
{
    LEFTAUX,
    RIGHTAUX,
    CENTRE,
    CENTRE2,
    CENTRE3,
    EXTERNAL1,
    EXTERNAL2,
    RIGHTTIP,
    LEFTTIP,
    LEFTMAIN,
    RIGHTMAIN
};
Code:
//**************************************************************************
//  Fuel Tank Capacity
//**************************************************************************
double getFuelCapacity(double tank)
{
    double capacity=0;
    char tank_name[50] = {0};

    if(tank==TANK::CENTRE)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK CENTER CAPACITY, gallons)");
    if(tank==TANK::CENTRE2)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK CENTER2 CAPACITY, gallons)");
    if(tank==TANK::CENTRE3)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK CENTER3 CAPACITY, gallons)");
    if(tank==TANK::LEFTAUX)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK LEFT AUX CAPACITY, gallons)");
    if(tank==TANK::RIGHTAUX)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK RIGHT AUX CAPACITY, gallons)");
    if(tank==TANK::LEFTTIP)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK LEFT TIP CAPACITY, gallons)");
    if(tank==TANK::RIGHTTIP)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK RIGHT TIP CAPACITY, gallons)");
    if(tank==TANK::EXTERNAL1)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK EXTERNAL1 CAPACITY, gallons)");
    if(tank==TANK::EXTERNAL2)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK EXTERNAL2 CAPACITY, gallons)");
    if(tank==TANK::LEFTMAIN)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK LEFT MAIN CAPACITY, gallons)");
    if(tank==TANK::RIGHTMAIN)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK RIGHT MAIN CAPACITY, gallons)");

    execute_calculator_code(tank_name, &capacity, NULL, NULL);

    return capacity;
}
//**************************************************************************
//  Fuel Tank Quantity
//**************************************************************************
double getFuelQuantity(double tank)
{
    double quantity=0;
    char tank_name[50] = {0};

    if(tank==TANK::CENTRE)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK CENTER QUANTITY, gallons)");
    if(tank==TANK::CENTRE2)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK CENTER2 QUANTITY, gallons)");
    if(tank==TANK::CENTRE3)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK CENTER3 QUANTITY, gallons)");
    if(tank==TANK::LEFTAUX)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK LEFT AUX QUANTITY, gallons)");
    if(tank==TANK::RIGHTAUX)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK RIGHT AUX QUANTITY, gallons)");
    if(tank==TANK::LEFTTIP)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK LEFT TIP QUANTITY, gallons)");
    if(tank==TANK::RIGHTTIP)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK RIGHT TIP QUANTITY, gallons)");
    if(tank==TANK::EXTERNAL1)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK EXTERNAL1 QUANTITY, gallons)");
    if(tank==TANK::EXTERNAL2)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK EXTERNAL2 QUANTITY, gallons)");
    if(tank==TANK::LEFTMAIN)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK LEFT MAIN QUANTITY, gallons)");
    if(tank==TANK::RIGHTMAIN)sprintf_s(tank_name, sizeof(tank_name), "(A:FUEL TANK RIGHT MAIN QUANTITY, gallons)");

    execute_calculator_code(tank_name, &quantity, NULL, NULL);

    return quantity;
}
The sample in the P3D SDK for 'SimConnect_SetDataOnSimObject' is a pointer to a struct, yes?
 

ddawson

Resource contributor
#11
You're writing the entire array of 11 tanks on each transfer calculation. The stock FS fuel vars only update once per second, so your Execute Calculator Code calls are probably loading obsolete data.
I would keep the writes to only the tanks you had altered.
 

ddawson

Resource contributor
#12
To follow up on this. Now that you've got me thinking about it, it's the infrequent updates on the fuel vars that had me using SimConnect to retrieve the current fuel tank levels. I think you will need to do the same.
 

DragonflightDesign

Resource contributor
#13
:rotfl:Just what I'm in the process of doing! I need to come back to this because I don't understand why REQUEST_FUEL_STATE_DATA isn't being hit. Got to be my definitions somewhere. I bet I'm in the wrong OnRecvXXXX. More research under way.
Code:
void OnRecvEvent(SIMCONNECT_RECV_EVENT *pEvent, DWORD cbData)
{
    switch (pEvent->uEventID)
    {
        case CLIENT_EVENT_4SEC:
        {
            // -----------------------------------------------------
            // Fuel state - comes through here OK
            hr = SimConnect_RequestDataOnSimObjectType(hSimConnect, REQUEST_FUEL_STATE_DATA, DEFINE_FUEL_LEVEL, 0, SIMCONNECT_SIMOBJECT_TYPE_USER);
Code:
// -----------------------------------------------------------------------------------------------------------------
void OnRecvSimobjectDataByType(SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE *pObjData, DWORD cbData)
{
    // Fuel state
    if (pObjData->dwRequestID == REQUEST_FUEL_STATE_DATA)
    {
// Never gets into here
        DWORD ObjectID = pObjData->dwObjectID;
        FUEL_LEVEL_DATA *pFSD = (FUEL_LEVEL_DATA*)&pObjData->dwData;
 
#14
This:
Code:
    // Write the data
    hRes = SimConnect_SetDataOnSimObject(hSimConnect, DEFINE_FUEL_LEVEL, SIMCONNECT_SIMOBJECT_TYPE_USER, NULL, NULL, sizeof(fuel_tanks), &fuel_tanks[0]);
isn't correct, it should be:
Code:
    // Write the data
    hRes = SimConnect_SetDataOnSimObject(hSimConnect, DEFINE_FUEL_LEVEL, SIMCONNECT_SIMOBJECT_TYPE_USER, NULL, 11, sizeof(double), &fuel_tanks[0]);
If you're going to send an array of 11 double values to the sim, you need to tell it there are 11 values of double size that start at &fuel_tanks[0].
 
#15
To add to the discussion, I use SimConnect for all fuel interactions... I obtain tank capacity from SimConnect_RequestDataOnSimObject passing SIMCONNECT_PERIOD_ONCE to ensure I only get caps once. I obtain tank levels from SimConnect_RequestDataOnSimObject passing SIMCONNECT_PERIOD_SIM_FRAME so I get it as quickly as the sim processes a frame. I don't recall why I chose that over SIMCONNECT_PERIOD_SECOND... but I know there was a reason I needed to. The only difference is that I have to calculate durations between each data read to control flow for transfers.
 
#16
Why are you using SimConnect_RequestDataOnSimObjectType???? You should NOT be using that. You should be using SimConnect_RequestDataOnSimObject
 

DragonflightDesign

Resource contributor
#17
Thanks Ed - I'm at work ATM so I can't try them just yet. Surprisingly, I'm enjoying this SimConnect learning process even though I seem to be making a complete b*ll*cks of it at times! As to why I was using SimConnect_RequestDataOnSimObjectType; I wrote that a long time ago so I can only guess at this stage that I misinterpreted something in the Simconnect SDK. Wouldn't have been the first time.
 
#18
Well, the function you're using is best for requests that are spurious and infrequent... if you need data returned in a reliable frequency, then you need the one I suggest.
 

JB3DG

Resource contributor
#19
This:
Code:
    // Write the data
    hRes = SimConnect_SetDataOnSimObject(hSimConnect, DEFINE_FUEL_LEVEL, SIMCONNECT_SIMOBJECT_TYPE_USER, NULL, NULL, sizeof(fuel_tanks), &fuel_tanks[0]);
isn't correct, it should be:
Code:
    // Write the data
    hRes = SimConnect_SetDataOnSimObject(hSimConnect, DEFINE_FUEL_LEVEL, SIMCONNECT_SIMOBJECT_TYPE_USER, NULL, 11, sizeof(double), &fuel_tanks[0]);
If you're going to send an array of 11 double values to the sim, you need to tell it there are 11 values of double size that start at &fuel_tanks[0].
Not correct. His first example was correct. If he adds 11 definitions to DEFINE_FUEL_LEVEL, then the 11 must be null, the sizeof be the size of the entire array, and the final arg is the address of the pointer to the beginning of the array (done this so many times in the sim so I know it is correct). His problems are elsewhere if he uses the first version.
 

DragonflightDesign

Resource contributor
#20
I'm convinced Doug was right about the 'problems elsewhere'; I didn't know that the update in FSX could be as slow as a second. So... after a full day struggling with SimConnect I can finally load the tank capacities on PERIOD_ONCE and tank levels on PERIOD_SECOND. I originally elected for PERIOD_FRAME as suggested by Ed, but then did a really, really, really good imitation of a rabbit caught in car headlights o_O when I considered the implications of the flow calculation. Along the way I've picked up a far better (but still very, very incomplete) understanding of how SimConnect presents the data to you.

Tomorrow... lets try dumping fuel again. I'll keep you updated.
 
Top