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

FSX Display Callsign String

Messages
78
Country
unitedkingdom
I am not a programmer of any type but if something is not available that I would like to use I do try and make it.
I've had lots of help from these forums over the years and I know this one is pretty simple for those that know how, but I don't know how.

I display information from the aircraft I'm flying in Teamspeak.
For instance I display the Squawk with the below code...

Code:
char SQUAWK[8];

struct _ComData
{
  double Transponder;
};

_ComData sCD = { 0., 0. };

double FSAPI Transponder()
{
  if (NULL == hSimConnect) return 0000;
  else return sCD.Transponder;
}

void OnRecvOpen(SIMCONNECT_RECV_OPEN *pData, DWORD cbData, void* pContext)
{
  hr = SimConnect_AddToDataDefinition(hSimConnect, COM_DEFINITION, "TRANSPONDER CODE:1", "Hz", SIMCONNECT_DATATYPE_FLOAT64);
}

sprintf_s(SQUAWK, "%4.0f", Transponder());

I would also like to display the Callsign /Registration of my Aircraft.

I believe I need hr = SimConnect_AddToDataDefinition(hSimConnect, COM_DEFINITION, "ATC ID", "", SIMCONNECT_DATATYPE_STRING32); to get the callsign but I have no idea how to display it as a string (%s).

Would I need to add it as below?
struct _ComData
{
double Callsign;
};

_ComData sCD = { 0., 0. };

double FSAPI Callsign()
{
if (NULL == hSimConnect) return None Set;
else return sCD.Callsign;
}

All help is appreciated.
 
I'm using
hr = SimConnect_AddToDataDefinition(hSimConnect, COM_DEFINITION, "ATC ID", NULL, SIMCONNECT_DATATYPE_STRING32);

sprintf_s(CALLSIGN, "%s");

But returned I get Callsign ,y{�(z{
 
You don't have your struct set up correctly - you want a string - you structure is a double. I assume your using C++?

See the Request Data example and use the title part. Assuming ATC_ID is a string (10).
 
Expect lots of stupid questions.....
But do I need the struct?
Can I not do something similar to Char CALLSIGN [256] and then printf("Callsign="%s", CALLSIGN)
 
This is what I have so far...

char CALLSIGN[256];

struct _ComData
{
char Callsign;
};

_ComData sCD = { 0., 0. };


char FSAPI Callsign()
{
if (NULL == hSimConnect) return 0;
else return sCD.Callsign;
}


hr = SimConnect_AddToDataDefinition(hSimConnect, COM_DEFINITION, "ATC ID", NULL, SIMCONNECT_DATATYPE_STRING256);

sprintf_s(CALLSIGN, "%s", Callsign()); generates a program crash
Where as
sprintf_s(CALLSIGN, "%c", Callsign()); does show the first Character of the Callsign.
 
You could try something like:

Code:
struct _ATCData
{
    char cCallsign[32];
};

     hr = SimConnect_AddToDataDefinition(hSimConnect, ATC_DEFINITION, "ATC ID", NULL, SIMCONNECT_DATATYPE_STRING32);

then in the Callback function:

Code:
          SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE*)pData;
        
            switch(pObjData->dwRequestID)
            {
                case ATC_REQUEST:
                {
                    _ATCData * pPointer = (_ATCData*)&pObjData->dwData;                  
                    char cBuff[32];
                    sprintf_s(cBuff,"%s",pPointer->cCallsign);

You should have the "ATC ID" string in pPointer->cCallsign.

Tom
 
Last edited:
Andy,

What Tom Said with the changes to the Request Data example.

There are no stupid questions ....

1. Simconnect sends data back and forth in packets so structures are important. Even a single piece of data - say a double needs to be put into a structure. Like a letter in an envelope.

so
Code:
char CALLSIGN[256];

struct _ComData
{
char Callsign;
};

should be like Tom's example (since the ATC ID is only 10 character (see SDK) use 32 instead of 256)

Code:
struct _ComData
{
char CALLSIGN[32];
};

you copied this from your other program, but it is not correct. You are working with a string and not a a double. I'm not familiar with char FSAPI.

Code:
_ComData sCD = { 0., 0. };

char FSAPI Callsign()
{
if (NULL == hSimConnect) return 0;
else return sCD.Callsign;
}

_ComData sCD - that makes a variable sCD of type _ComData (the structure), but you initialize it to two floats. Did you get a warning?

Code:
hr = SimConnect_AddToDataDefinition(hSimConnect, COM_DEFINITION, "ATC ID", NULL, SIMCONNECT_DATATYPE_STRING256);

is okay but use STRING32 instead of STRING256 if you change your struct.

Code:
sprintf_s(CALLSIGN, "%s", Callsign()); generates a program crash
Where as
sprintf_s(CALLSIGN, "%c", Callsign()); does show the first Character of the Callsign.

crash because of the float initialization - I think.

You get the first character because Callsign() points to the first memory location - only has the first character. No knowing your code - structures would use sCD->CALLSIGN.
The sCD variable (structure and get the member variable CALLSIGN (note the uppercase - C/C++ C# are case sensitive.)

Now after all that - rework the Request Data example and make the changes Tom suggested. It works.

When you run the console program - to trigger the display of the ATC ID you need to run FSX - run the console prgram. When in flight - hit esc the click on continue flying - this triggers the Sim Stop, Sim Start where the request is triggered, otherwise you don't see the ATC ID.
 
Thank you both Tom and Ron.

I've played with the code I have for most of the night and ashamed to say I'm still clueless.

I retrieve the Double information just fine and I have included below how I do that.

I just can't seem to convert the way I display the doubles to strings, or include that what you have suggested above.

Code:
char FREQ[8];
char FREQ2[8];
char FREQS[8];
char FREQ2S[8];
char SQUAWK[8];
char QNH[8];
char QNHA[8];
char ALT[8];

struct _ComData
{
  double Com1;
  double Com2;
  double Com1s;
  double Com2s;
  double Transponder;
  double qnh;
  double qnha;
  double altitude;

};

_ComData sCD = { 0., 0. };


double FSAPI GetCom1()
{
  if (NULL == hSimConnect) return 999.999;
  else return sCD.Com1;
}

double FSAPI GetCom2()
{
  if (NULL == hSimConnect) return 999.999;
  else return sCD.Com2;
}

double FSAPI GetCom1s()
{
  if (NULL == hSimConnect) return 999.999;
  else return sCD.Com1s;
}

double FSAPI GetCom2s()
{
  if (NULL == hSimConnect) return 999.999;
  else return sCD.Com2s;
}

double FSAPI Transponder()
{
  if (NULL == hSimConnect) return 0000;
  else return sCD.Transponder;
}

double FSAPI qnh()
{
  if (NULL == hSimConnect) return 1013;
  else return sCD.qnh;
}

double FSAPI qnha()
{
  if (NULL == hSimConnect) return 29.92;
  else return sCD.qnha;
}
double FSAPI altitude()
{
  if (NULL == hSimConnect) return 0;
  else return sCD.altitude;
}


void OnRecvOpen(SIMCONNECT_RECV_OPEN *pData, DWORD cbData, void* pContext)
{
  hr = SimConnect_AddToDataDefinition(hSimConnect, COM_DEFINITION, "COM ACTIVE FREQUENCY:1", "Mhz", SIMCONNECT_DATATYPE_FLOAT64);
  hr = SimConnect_AddToDataDefinition(hSimConnect, COM_DEFINITION, "COM STANDBY FREQUENCY:1", "Mhz", SIMCONNECT_DATATYPE_FLOAT64);
  hr = SimConnect_AddToDataDefinition(hSimConnect, COM_DEFINITION, "COM ACTIVE FREQUENCY:2", "Mhz", SIMCONNECT_DATATYPE_FLOAT64);
  hr = SimConnect_AddToDataDefinition(hSimConnect, COM_DEFINITION, "COM STANDBY FREQUENCY:2", "Mhz", SIMCONNECT_DATATYPE_FLOAT64);
  hr = SimConnect_AddToDataDefinition(hSimConnect, COM_DEFINITION, "TRANSPONDER CODE:1", "Hz", SIMCONNECT_DATATYPE_FLOAT64);
  hr = SimConnect_AddToDataDefinition(hSimConnect, COM_DEFINITION, "KOHLSMAN SETTING MB", "Millibars", SIMCONNECT_DATATYPE_FLOAT64);
  hr = SimConnect_AddToDataDefinition(hSimConnect, COM_DEFINITION, "KOHLSMAN SETTING HG", "inHg", SIMCONNECT_DATATYPE_FLOAT64);
  hr = SimConnect_AddToDataDefinition(hSimConnect, COM_DEFINITION, "INDICATED ALTITUDE", "feet", SIMCONNECT_DATATYPE_FLOAT64);
  hr = SimConnect_RequestDataOnSimObject(hSimConnect, COM_REQUEST, COM_DEFINITION, SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD_SECOND, SIMCONNECT_DATA_REQUEST_FLAG_CHANGED);
}


void OnRecvSimobjectData(SIMCONNECT_RECV_SIMOBJECT_DATA *pData, DWORD cbData, void* pContext)
{
  switch (pData->dwDefineID)
  {
  case COM_DEFINITION:
  CopyMemory(&sCD, &pData->dwData, sizeof(sCD));
  break;
  }
}

  sprintf_s(FREQ, "%3.3f", GetCom1());
  sprintf_s(FREQ2, "%3.3f", GetCom2());
  sprintf_s(FREQS, "%3.3f", GetCom1s());
  sprintf_s(FREQ2S, "%3.3f", GetCom2s());
  sprintf_s(ALT, "%3.0f", altitude());
  sprintf_s(QNH, "%2.0f", qnh());
  sprintf_s(QNHA, "%4.2f", qnha());
  sprintf_s(SQUAWK, "%4.0f", Transponder());

 snprintf("Com 1 Active: %s Mhz Standby:  %s Mhz\nCom 2 Active: %s Mhz Standby:  %s Mhz\nAltitude is:  %s ft \nQNH:  %s or   %s Altimeter Setting\nSquawking:  %s", FREQ, FREQ2, FREQS, FREQ2S, ALT, QNH, QNHA, SQUAWK);
 
What language are you using c++ or C#?
Any other files like a something.h

Where is FSAPI declared? I've seen it but forget where
 
ok I also assume this is a DLL too and not an exe. Just want to replicate what you are trying to do.

So you basically want to add a string to your struct there with all the frequencies.

Code:
struct _ComData
{
  char ATCid[32];
  double Com1;
  double Com2;
  double Com1s;
  double Com2s;
  double Transponder;
  double qnh;
  double qnha;
  double altitude;
};

then add in the extra addtodatadefnition.

Code:
hr = SimConnect_AddToDataDefinition(hSimConnect, COM_DEFINITION, "ATC ID", NULL, SIMCONNECT_DATATYPE_STRING32);

There is no need for the sprinf_s for the already string data for the ATCid.

Code:
snprintf("Com 1 Active: %s Mhz Standby:  %s Mhz\nCom 2 Active: %s Mhz Standby:  %s Mhz\nAltitude is:  %s ft \nQNH:  %s or   %s Altimeter Setting\nSquawking:  %s \nATC ID: %s", FREQ, FREQ2, FREQS, FREQ2S, ALT, QNH, QNHA, SQUAWK, ATCid);
 
Thank you Ron yes it is a .dll for Teamspeak but I still have no joy.
Maybe I should have said that my printf is in a void ?
Code:
void ts3plugin_infoData(uint64 serverConnectionHandlerID, uint64 id, enum PluginItemType type, char** data) {


  *data = (char*)malloc(INFODATA_BUFSIZE * sizeof(char));  /* Must be allocated in the plugin! */

  sprintf_s(FREQ, "%3.3f", GetCom1());
  sprintf_s(FREQ2, "%3.3f", GetCom2());
  sprintf_s(FREQS, "%3.3f", GetCom1s());
  sprintf_s(FREQ2S, "%3.3f", GetCom2s());
  sprintf_s(ALT, "%3.0f", altitude());
  sprintf_s(QNH, "%2.0f", qnh());
  sprintf_s(QNHA, "%4.2f", qnha());
  sprintf_s(SQUAWK, "%4.0f", Transponder());
   
  snprintf(*data, INFODATA_BUFSIZE, "Com 1 Active:[COLOR=#437C17][B] %s[/B][/COLOR] Mhz Standby:[COLOR=#E56717][B]  %s[/B][/COLOR] Mhz\nCom 2 Active:[COLOR=#437C17][B] %s[/B][/COLOR] Mhz Standby:[COLOR=#E56717][B]  %s[/B][/COLOR] Mhz\nAltitude is:[COLOR=#151B8D][B]  %s[/B][/COLOR] ft \nQNH:[COLOR=#151B8D][B]  %s[/B][/COLOR] or [COLOR=#151B8D][B]  %s[/B][/COLOR] Altimeter Setting\nSquawking:[COLOR=#151B8D][B]  %s[/B][/COLOR]\nCallsign: %s ", FREQ, FREQ2, FREQS, FREQ2S, ALT, QNH, QNHA, SQUAWK, ATCid);

}

If I add as you suggested I get an undeclared identifier.

If I add the Char within the void and not in the struct I get an out of memory error and crash in Teamspeak.
 
Did you try:

Code:
char ATC_ID[32];

struct _ComData
{
   char ATCid[32];
   ...rest of the members
};

_ComData sCD;

char * cAtcID()
{
   return (NULL == hSimConnect) ? "NO ATC" : sCD.ATCid;
}

sprintf_s(ATC_ID "%s", cAtcID());

Then

Code:
snprintf(*data, INFODATA_BUFSIZE, "Com 1 Active:[COLOR=#437C17][B] %s[/B][/COLOR] Mhz Standby:[COLOR=#E56717][B] %s[/B][/COLOR] Mhz\nCom 2 Active:[COLOR=#437C17][B] %s[/B][/COLOR] Mhz Standby:[COLOR=#E56717][B] %s[/B][/COLOR] Mhz\nAltitude is:[COLOR=#151B8D][B] %s[/B][/COLOR] ft \nQNH:[COLOR=#151B8D][B] %s[/B][/COLOR] or [COLOR=#151B8D][B] %s[/B][/COLOR] Altimeter Setting\nSquawking:[COLOR=#151B8D][B] %s[/B][/COLOR]\nCallsign: %s ", FREQ, FREQ2, FREQS, FREQ2S, ALT, QNH, QNHA, SQUAWK, ATC_ID);

I think it should work, otherwise what kind of error returns?

Tom
 
Last edited:
Tom you've cracked it.

I now have the tail number of my aircraft displaying.

I'm sure I'd tried that?????

Thank you both Tom and Ron, I probably would have been here for years if it wasn't for your help.
 
Good.
Now that you have it working, I would like to give you other perspective to avoid writing unnecessary code.

For example, instead of using too many functions and assignmets like:

Code:
char FREQ[8];
char FREQ2[8];
char FREQS[8];
....etc
double FSAPI GetCom1(){ etc }
double FSAPI GetCom2(){ etc }
double FSAPI altitude(){ etc }
...etc
sprintf_s(FREQ, "%3.3f", GetCom1());
sprintf_s(FREQ2, "%3.3f", GetCom2());
...etc

you coud improve the code by defining, declaring and initializing _ComData structure in a single pass:

Code:
struct _ComData
{
  double Com1 ;
  double Com2;
  double Com1s;
  double Com2s;
  double Transponder;
  double qnh;
  double qnha;
  double altitude;
  char atc_id[32];
} sCD = { 999.999,999.999,999.999,999.999,0000,1013,29.92,0,"NO_ATC" };

Just be careful to pass the default values in proper place.

You can use #define to simplify writing of struct members:

Code:
#define  FREQ        sCD.Com1
#define  FREQ2      sCD.Com2
#define  FREQS      sCD.Com1s
#define  FREQ2S    sCD.Com2s
#define  SQUAWK   sCD.Transponder
#define  QNH         sCD.qnh
#define  QNHA       sCD.qnha
#define  ALT         sCD.altitude
#define  ATC_ID    sCD.atc_id

Finally, you can abbreviate ts3plugin_infoData function:

Code:
void ts3plugin_infoData(uint64 serverConnectionHandlerID, uint64 id, enum PluginItemType type, char** data)
{
     *data = (char*)malloc(INFODATA_BUFSIZE * sizeof(char)); /* Must be allocated in the plugin! */

      snprintf(*data, INFODATA_BUFSIZE, "Com 1 Active:[COLOR=#437C17][B] %3.3f[/B][/COLOR] Mhz Standby:[COLOR=#E56717][B] %3.3f[/B][/COLOR] Mhz\nCom 2 Active:[COLOR=#437C17][B] %3.3f[/B][/COLOR] Mhz Standby:[COLOR=#E56717][B] %3.3f[/B][/COLOR] Mhz\nAltitude is:[COLOR=#151B8D][B] %3.0f[/B][/COLOR] ft \nQNH:[COLOR=#151B8D][B] %2.0f[/B][/COLOR] or [COLOR=#151B8D][B] %4.2f[/B][/COLOR] Altimeter Setting\nSquawking:[COLOR=#151B8D][B] %4.0f[/B][/COLOR]\nCallsign: %s ", FREQ, FREQ2, FREQS, FREQ2S, ALT, QNH, QNHA, SQUAWK, ATC_ID);

}
Always check to not exceed INFODATA_BUFSIZE, otherwise the rest of characters will be discarded.

Tom
 
Last edited:
Thanks Tom.
I do need to tidy the code up and will implement this as well.
Thanks again for the help.
 
Before I go.......

And pushing my luck a bit further here. ;)

What am I missing?
Code:
if (cTitle() == "Tower Controller") {
  snprintf(*data, INFODATA_BUFSIZE, "Com 1:[COLOR=#437C17][B] %s[/B][/COLOR] Mhz\nCom 2:[COLOR=#437C17][B] %s[/B][/COLOR] Mhz \n[COLOR=#151B8D][B]You are an Air Traffic Controller[/B][/COLOR]", FREQ, FREQS);
  }
Title does display correctly as a Printf String so I do receive the data.
But this data I do not want to show, I only need to use it to display something else.
 
Andy,

What kind of data do you need to display in that case?

I mean, do you want *data buffer filled with what?

Besides, is in ts3plugin_infoData function where you want to construct your char buffer, or you actually want to check its content in other place of the code and build another structure/display something else according to what is contained in the buffer?

Tom
 
Hi Tom,

The actual Data buffer and displayed data does what I expect, but I'm having problems with the if statement.

if (cTitle() == "Tower Controller")

CTitle is a char and is included correctly in that it will printf if I would like it too, but I don't need it too.

I just need to know that if the Aircraft is a Tower Controller to display the Frequencies FREQ and FREQS.

I do something similar with a double using the code below.

Code:
if (GetCom1() > 136.999 || GetCom1() < 118.000) {
    snprintf(*data, INFODATA_BUFSIZE, "[COLOR=#E42217][B]DATA IS NOT AVAILABLE![/B][/COLOR]"); }
 
Oh ok I see.

Just use strcmpi :

if( strcmpi( (const char*)cTitle(),"Tower Controller" ) == 0)
{ do something }

int strcmpi( const char * buff1, const char * buff2 )
-> returns 0 if both values are exactly the same, ignoring case. Then "Tower Controller" and "TOWER CONTROLLER" are treated as equal.

int strcmp( const char * buff1, const char * buff2 )
-> same as previous, but case sensitive.

You need to typecast cTitle() if it is a char * function

Tom
 
Back
Top