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

Does managed simconnect support tagged data retrieval?

Messages
13
Country
canada
I saw a really old post that said that beatle hadn't implemented it yet, but maybe things have changed. If it is supported, can anybody point me to a simple code example? I know how to do it in C++, but I'm not really good with C# / data marshalling. I basically need help with code like this:

C#:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct Struct1 {
    public uint id;
    public uint value;
};

      // Set up all the SimConnect related event handlers
      private void initClientEvent() {
         try {
            // listen to connect and quit msgs
            simconnect.OnRecvOpen += new SimConnect.RecvOpenEventHandler(simconnect_OnRecvOpen);
            simconnect.OnRecvQuit += new SimConnect.RecvQuitEventHandler(simconnect_OnRecvQuit);

            // avionics
            simconnect.AddToDataDefinition(DEFINITIONS.Struct1, "COM ACTIVE FREQUENCY:1", "Frequency BCD16", 
                  SIMCONNECT_DATATYPE.INT32, 0.0f, (uint) DATA_NAMES.Com1Active);
            simconnect.AddToDataDefinition(DEFINITIONS.Struct1, "COM ACTIVE FREQUENCY:2", "Frequency BCD16", 
                  SIMCONNECT_DATATYPE.INT32, 0.0f, (uint)DATA_NAMES.Com2Active);
            simconnect.AddToDataDefinition(DEFINITIONS.Struct1, "COM STANDBY FREQUENCY:1", "Frequency BCD16", 
                  SIMCONNECT_DATATYPE.INT32, 0.0f, (uint)DATA_NAMES.Com1Standby);
            simconnect.AddToDataDefinition(DEFINITIONS.Struct1, "COM STANDBY FREQUENCY:2", "Frequency BCD16",
                  SIMCONNECT_DATATYPE.INT32, 0.0f, (uint)DATA_NAMES.Com2Standby);

            simconnect.RegisterDataDefineStruct<Struct1>(DEFINITIONS.Struct1);

            simconnect.RequestDataOnSimObject(REQUESTS.Request1, DEFINITIONS.Struct1, SimConnect.SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD.SIM_FRAME,
               SIMCONNECT_DATA_REQUEST_FLAG.CHANGED | SIMCONNECT_DATA_REQUEST_FLAG.TAGGED, 0, 0, 0);

            // catch a simobject data request
            simconnect.OnRecvSimobjectData += new SimConnect.RecvSimobjectDataEventHandler(simconnect_OnRecvSimobjectData);
            
         }
         catch (COMException ex) {
            displayText(ex.Message);
         }
      }

void simconnect_OnRecvSimobjectData(SimConnect sender, SIMCONNECT_RECV_SIMOBJECT_DATA data) {

         switch ((REQUESTS)data.dwRequestID) {

            case REQUESTS.Request1:
  
               // I specified tagged data on the request, so dwData actually points to an array, but
               // I only know how to access the first element
               Struct1 s1 = (Struct1)data.dwData[0];
               displayText("data " + Bcd2Dec(s1.value).ToString());

               break;

            default:
               displayText("Unknown request ID: " + data.dwRequestID);
               break;
         }
      }
 
Last edited:
Well after some fiddling, I managed to get something to work. See the code fragments below, in case anyone else comes along looking to do the same thing. The only thing I'm not happy with is I had to hard code the size of the array with the constant MAX_DATA_ELEMENTS. It would be nice if there was some way to utilize a variable length array.

C#:
enum DEFINITIONS {
   Struct1,
}

enum REQUESTS {
   Request1
}

// be sure to update this if you add more elements.
const int MAX_DATA_ELEMENTS = 2;

enum DATA_NAMES {
   Com1Active,
   Com1Standby,
}


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct OneItem {
   public uint id;
   public uint value;
}

[StructLayout(LayoutKind.Sequential)]
public struct DataItems {
   [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = MAX_DATA_ELEMENTS)]
   public OneItem[] data;
}


// Set up all the SimConnect related event handlers
private void initClientEvent() {
   try {
      // listen to connect and quit msgs
      simconnect.OnRecvOpen += new SimConnect.RecvOpenEventHandler(simconnect_OnRecvOpen);
      simconnect.OnRecvQuit += new SimConnect.RecvQuitEventHandler(simconnect_OnRecvQuit);

      // listen to exceptions
      simconnect.OnRecvException += new SimConnect.RecvExceptionEventHandler(simconnect_OnRecvException);

      // data definitions
      simconnect.AddToDataDefinition(DEFINITIONS.Struct1, "COM ACTIVE FREQUENCY:1", "Frequency BCD16",
            SIMCONNECT_DATATYPE.INT32, 0.0f, (uint)DATA_NAMES.Com1Active);
      simconnect.AddToDataDefinition(DEFINITIONS.Struct1, "COM STANDBY FREQUENCY:1", "Frequency BCD16",
            SIMCONNECT_DATATYPE.INT32, 0.0f, (uint)DATA_NAMES.Com1Standby);

      simconnect.RegisterDataDefineStruct<DataItems>(DEFINITIONS.Struct1);

      simconnect.RequestDataOnSimObject(REQUESTS.Request1, DEFINITIONS.Struct1, SimConnect.SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD.SIM_FRAME,
         SIMCONNECT_DATA_REQUEST_FLAG.CHANGED | SIMCONNECT_DATA_REQUEST_FLAG.TAGGED, 0, 0, 0);

      // catch a simobject data request
      simconnect.OnRecvSimobjectData += new SimConnect.RecvSimobjectDataEventHandler(simconnect_OnRecvSimobjectData);
      
   }
   catch (COMException ex) {
      displayText(ex.Message);
   }
}

void simconnect_OnRecvSimobjectData(SimConnect sender, SIMCONNECT_RECV_SIMOBJECT_DATA data) {

   switch ((REQUESTS)data.dwRequestID) {

      case REQUESTS.Request1:

         DataItems s2 = (DataItems)data.dwData[0];

         for (int i = 0; i < data.dwDefineCount; i++) {

            switch ((DATA_NAMES)s2.data[i].id) {

               case DATA_NAMES.Com1Active:
                  // data is in s2.data[i].value
                  break;

               case DATA_NAMES.Com1Standby:
                  // data is in s2.data[i].value
                  break;

               default:
                  break;
            }
         }

         break;

      default:
         displayText("Unknown request ID: " + data.dwRequestID);
         break;
   }
}
 
A few comments, some of which you'll know, some of which will be useful to other people:
Code:
      simconnect.RequestDataOnSimObject(REQUESTS.Request1, DEFINITIONS.Struct1, SimConnect.SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD.SIM_FRAME,
         SIMCONNECT_DATA_REQUEST_FLAG.CHANGED | SIMCONNECT_DATA_REQUEST_FLAG.TAGGED, 0, 0, 0);
Unless you absolutely need to do nothing until the request flag is changed, this would be a better option:-
Code:
      simconnect.RequestDataOnSimObject(REQUESTS.Request1, DEFINITIONS.Struct1, SimConnect.SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD.SIM_FRAME,
         SIMCONNECT_DATA_REQUEST_FLAG.DEFAULT, 0, 0, 0);
- and ignore non-changed data in later code (if necessary).

Simconnect demands that the struct into which you are placing data is the same size as the data definition struct. It's not an array. Also (and this caught me out badly at first - I'm still kicking myself for not spotting the obvious) the data that hits the receiving struct is a struct of pointers to the actual data, so it only has a lifetime of one clock tick. You have to get it out on the same pass and store it somewhere with a greater lifetime. In C/C++ I drop it into another struct (same struct declaration: one is the struct to to accept the pointers and the other stores the actual data from the pointers). In dotNet I'm lazy and drop it into an array immediately after the pointers become available.

This probably obvious to you, but never forget that the managed stuff in Simconnect is only a COM wrapper to talk to the C++ code.
 
Back
Top