Reading and writing Lvar from C++

#21
I looked into that , but I was not sure that SimConnect "commands" could be used within a DLL that is running in the P3Dv4 process. I was looking for some FSAPI "commands".

To me this looks like going out of the process and then back again. But, my knowledge of P3Dv4 DLL programming has just started to build up, so I have a try.
 

ddawson

Resource contributor
#22
Go to my website and download
p3d_xml_vars_x64
It is a gauge that you can to the panel of a test aircraft. It will allow you to scroll through all lvars active in the session, giving you the ID, the name and the current value.
 
#23
I have some trouble to get my head around the DLL programming in general and the lvar_interface dll

Lets say I just want to get the value of lvar "B767_AT_Arm_Sw"

Shouldn't that be done with the

GetLVarByName("B767_AT_Arm_Sw");


But, where in the dll code " dllmain.cpp" should it be?

Where does the actual code execution start?


here?

case DLL_PROCESS_ATTACH:
{
GetLVarByName("B767_AT_Arm_Sw");
}



I have only done C++ executable programming , not any DLL coding
 

ddawson

Resource contributor
#24
You need to create a routine to handle the communications with your external app.
That routine is best initiated from within DLLStart().
The functions listed in lvar_interface.cpp will be called, as required from within your communications routine.
 
#25
Go to my website and download
p3d_xml_vars_x64
It is a gauge that you can to the panel of a test aircraft. It will allow you to scroll through all lvars active in the session, giving you the ID, the name and the current value.

Tried it , but I didn't get it to work. The window comes up, but it is just a dark window. Probably my bad.

Where do the dll go? In the P3Dv4/Gauges folder or P3Dv4 main folder or somewhere else?

Or should it be started from the dll.xml file?

I have tried most alternatives listed above, but with no luck.



UPDATE:

Got it working after renaming the dll to xml_vars.gau


Working now fine, thanks.
 
Last edited:
#26
I really liked the p3d_xlm_vars_64.dll I downloaded . it help me during the debug phase of my program.

It it possible for you to add some new features to it?

Like,
Increase outpu lines from 20 to lets say 100
Filterering of displayed lvar name
Copy function of all lines to clipboard for pasting to editor(NotePad)


If you do not have time, is the source available to modify?
 
#28
I know I can scroll with mouse, but more visible lines(lvars) would be better(at leaset for my purpose).

The nicest would be a fixed font size and an increased/decreased number of lines when increasing/decreasing the window with mouse.

A filtering function is the most important though.
 
#29
You need to create a routine to handle the communications with your external app.
That routine is best initiated from within DLLStart().
The functions listed in lvar_interface.cpp will be called, as required from within your communications routine.
I have added the code for initiating a communication client and it sets up a connection to the communication server( my C++ app)

After the initialization of the comm.client, P3D takes over.

I guess I need to create separate threads for reading/setting lvar values and reading/sending on the comm link.

These threads should not be started before the actual airplane I want to read/set lvar from.

This is my challenge and anyone who can share some hints of how to do this are welcomed.

I have tried to create these threads, but without success.


Is it possible to create threads in the DLLStart function?
 
#31
Got the comm thread working now by using the


hcommThread = CreateThread(NULL, 1024, my_comm, NULL, 0, &ThreadID)

The _beginthread in your link I didn't know about. Is there a preferred one when programming in the P3D environment or are they more or less the same?
 
#33
I have more or less finished my DLL project and are doing some testing to improve the performance.


I have a threadin my DLL that reads an airplane LVar values implemented as shown second code part below. It is , I believe, not a professional way of doing it , but it works.

Is there a better way to code this function, i.e. with a Callback function as found in SimConnect? See code below.

Code:
int hr = SimConnect_CallDispatch(hndl, MyDispatchProc, NULL);

void CALLBACK MyDispatchProc(SIMCONNECT_RECV* pData, DWORD cbData, void *pContext)
{

    switch (pData->dwID)
    {
    case SIMCONNECT_RECV_ID_SIMOBJECT_DATA:       // Receive and process the FSX DATA block
    {
        SIMCONNECT_RECV_SIMOBJECT_DATA *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA*)pData;
        switch (pObjData->dwRequestID)
        {
        case SIM_REQ:
        {

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

            SIM_SPD = pS->speed;
I.e. having the Callback result ( that only report changes) sent to switch, so not every LVars have to read all the time as in my code now.

Is there any examples available how to do this in the most efficient way? How do you write the Callback and how

Code:
while (airplane_running)
    {

MCP_AP_master_CAPTAIN = (int)GetLVarByID(1);

MCP_AP_master_FO = (int)GetLVarByID(2);
MCP_AT_mode = (int)GetLVarByID(3);
// and so on for all Lvars too be read

// .....

    if (MCP_AP_master_CAPTAIN == 1)
    {sendVarData(1414, 1);
    }else { sendVarData(1414, 0); }
    if (MCP_AP_master_FO == 1)
    {sendVarData(1415, 1);
    }else { sendVarData(1415, 0); }
    
    // on so on
 

JB3DG

Resource contributor
#34
I make a single data definition using some obscure variable like IS USER SIM, and then I make a request data on simobject call that has the parameters set for it to return data every sim frame. Then I run my functions in the case where that request ID is hit.
 
#35
I follow you on the last parts of your answer, but the
"I make a single data definition using some obscure variable like IS USER SIM",

I really do not understand. Could you try to explain this more in detail not only for me, but for others that are heading into DLL coding.
 

ddawson

Resource contributor
#36
Jon is suggesting one way to get a callback on every sim frame - use RequestDataOnSimObject with a callback frequency of SIMCONNECT_PERIOD_SIM_FRAME.
Alternatively, you could call SubscribeToSystemEvent to request notification on each sim frame.
In actual fact, for external communications, such as you are considering, I think you might find that updating on each frame is a bit too much. I would start with the 6Hz or even 1sec notifications.

Also, it looks like you are hard coding the LVar ID's into your code. You can't do that, as you cannot rely on a given LVar having the same ID number in each session. You will need to check the ID number of each LVar before you access it. The ID numbers will be consistent over the life of the loaded aircraft, so you don't have to call check_named_variable in front of each call to get_named_variable_value.

Unfortunately, there is no way of knowing whether a particular LVar has changed values other than by reading it and comparing its current value to its previous value. This does mean that you will have to go through the entire list of LVars you are interested in each time you want to provide updated values - hence my suggestion to start with 6Hz rather than on each sim frame.
 
#37
Jon is suggesting one way to get a callback on every sim frame - use RequestDataOnSimObject with a callback frequency of SIMCONNECT_PERIOD_SIM_FRAME.
Alternatively, you could call SubscribeToSystemEvent to request notification on each sim frame.
In actual fact, for external communications, such as you are considering, I think you might find that updating on each frame is a bit too much. I would start with the 6Hz or even 1sec notifications.
This is what I do for the Simconnect Variables I have, as some of the airplane's variables are done as Simconnect Variables.

Also, it looks like you are hard coding the LVar ID's into your code. You can't do that, as you cannot rely on a given LVar having the same ID number in each session. You will need to check the ID number of each LVar before you access it. The ID numbers will be consistent over the life of the loaded aircraft, so you don't have to call check_named_variable in front of each call to get_named_variable_value.
This was new for me. I thought the ID was hardcoded and therefore the same for all sessions. Thanks for letting me know this important fact. Then I will go over to use Lvars names instead of IDs.

Unfortunately, there is no way of knowing whether a particular LVar has changed values other than by reading it and comparing its current value to its previous value. This does mean that you will have to go through the entire list of LVars you are interested in each time you want to provide updated values - hence my suggestion to start with 6Hz rather than on each sim frame.
Ok, so I keep my LVars reading code, just change from using ID to Name when addressing Lvars.

Not sure I know how to do
hence my suggestion to start with 6Hz rather than on each sim frame.
when reading LVars other than adding a Sleep(200) in the while(airplane_running) loop.


Again, thanks a lot for the feedback.
 
#38
I have my DLL working fine, but I want it to be active only when a specific airplane is loaded.

If another airplane is selected/loaded, the DLL should be deactivated.

I haven't found a good way of doing this yet. I know I could look for loaded airplane via SimConnect, and if not loaded, deactive all the DLL's active threads and if loaded again, active the threads.



I tried to rename it to a gau file and copied it the the Gauges folder and set it up in the panel.cfg of the airplane, but P3D crashes.

My understanding of gau vs dll, is that they are the same. Doing it this way should also have it active when the specific airplane is active.


Any ideas how to do this?
 
Last edited:

ddawson

Resource contributor
#40
The way you have things set up, there really isn't a good way to keep the module inactive when not in use.
It doesn't matter how you want to identify a relevant aircraft, you are going to have to deal with the fact that users can rename things (aircraft folders, .air files, title strings.) How are you going to deal with aftermarket repaints?
You could put a gauge on the panel of the relevant aircraft. Its presence would tell the module to activate. Then you have to offer support to people who can't or won't modify panel.cfg files.

I'm going to reiterate my suggestion that you make the module the server and your external app the client.
That way, the module will only be active when it is responding to input from the app. In the context of cpu cycles, this amounts to virtually never, which is precisely what you want for an in-process add-on.
 
Top