Demo: LVAR write access for any aircraft control

Thanks, learning something new every day.

Super! This was probably the most informative reading I’ve found on this subject. Thank you for taking the time to share!

2 Likes

So, I downloaded your code and added a PCSTRINGZ array with the H events that Working Title published for the FMS:

PCSTRINGZ FMS_BUTTONS[67] = {
  "(>H:CJ4_FMC_1_BTN_IDX)",
  ...
};

In the switch statement I added:

case 0x11010: {
  execute_calculator_code(FMS_BUTTONS[evdata], nullptr, nullptr, nullptr);
  break;
}

Visual Studio complained about the size of MCDU_BUTTONS[71] but after changing that to 72 it compiled without problem. I added the .wasm file to the community folder with the required .json files as your instructions:

  • WASM_lvar_access
    • module
      - WASM_lvar_access.wasm
    • layout.json
    • manifest.json

I already had the MobiFlight wasm module so I removed that to avoid any conflicts.

Finally I made an .evt file for FSUIPC with all the FMS events and mapped my keyboard numpad to the FMS buttons for 0-9. Nothing happened.

Obviously I’m missing something here but I don’t know what. Perhaps you or anyone else here could nudge me in the right direction :slightly_smiling_face:.

Hi @andhog, I gave this a quick try by only adding the following two lines to my local copy of the code:

PCSTRINGZ CJ4_BUTTONS[] = {
	"(>H:CJ4_FMC_1_BTN_A)",
	"(>H:CJ4_FMC_1_BTN_IDX)",
};

And using the case structure as before, with your event ID 0x11010. This works fine for me, at least when I directly interface through my SimConnect methods, thus Event 0x11010 with evdata 0x0 pushes button A, and Event ID with evdata 0x1 pushes IDX.

Have you checked that your layout.json properly reflects the new file size of the wasm module after compilation? I am unfamiliar with .evt files, so I am afraid I can’t help you there.

PS: thanks for noting the wrong index count in the GitHub copy of the source file.

1 Like

There’s most likely something wrong with my FSUIPC settings. Thank you for checking it out though, at least I know where to look now!

Still struggling to be able to read an LVAR with the get_named_varable().

If you could give me some more hints to make the code I would appreciate it a lot.

Any idea what the difference is between a >L: and L: before the var name?

1 Like

To read the value of an LVar that has been defined elsewhere:

int id = check_named_variable( "MyVariable" );

if ( id != -1 ))
  double value = get_named_variable_value( id );

To write the value of an LVar that has been defined elsewhere:

double value = 1234

int id = check_named_variable( "MyVariable" );
if ( id != -1 ))
 set_named_variable_value( id, value );

To define a new LVar:

int id = check_named_variable( "MyVariable" );

if ( id == -1 ))
  int id = register_named_variable( "MyVariable" );

the > sign in used in XML expressions to indicate the expression will write to the LVar, otherwise it’s a read.

1 Like

Thanks a lot, I have got it to work now.

Now hopefully the last issue is:

How to read those Lvars values that are read as described above from an external Simconnect client (exe)?

How to read those Lvars values that are read as described above from an external Simconnect client (exe)?

You can’t directly.

You must read them from a WASM module, then use the Simconnect data tagging functions to send them to a Simconnect client that will use the matching function to “listen” for your data.

Unfortunately, there’s no sample in the SDK so, you will have to figure it out only from the documentation.

Does anyone has an example of how to set up the “Simconnect data tagging functions”?
What type of Simconnect functions are tagging functions?

1 Like

Thanks everyone in this thread. I’ve been eyeing this for a while and appreciate all the information shared.

I was wondering the same, so I implemented GetClientData/SetClientData: GitHub - davuxcom/fs-gauge-bridge

BridgeGauge.wasm communicates with BridgeClient, an external SimConnect app in C#.

I did not use the data tagging as I don’t think it’s necessary, but optimizing this into a batch set of operations could benefit from that. Ultimately you have a data region and can do as you wish, however there is functionality to get updates only on part of the data changing.

It creates two client data areas, one that is used to send a string into a wasm, and one that is used to read a double from the wasm. There is a simple UI that lets you enter a value like (A:LIGHT LANDING,Bool) or 1 (>A:LIGHT LANDING,Bool) and then the value will be continually monitored. In the wasm the last query is checked and SetClientData is called on every frame.

Some additional notes:

  • Might not be optimal for performance. I see 60fps in all my testing though. The obvious next step is to read 10 strings at a time and output 10 values.
  • Not sure about memory leaks, but looks okay. Using shared_ptr and string should help
 obviously one string is held until gauge exit.
  • All work is done via execute_calculator_code. The named value stuff didn’t work for me and also doesn’t seem at all necessary unless I need to register them myself.
  • Possibly only start the BridgeClient app after the gauge is loaded, but I think this isn’t necessary. The client data regions are owned by the gauge but the client shouldn’t have a problem linking up the strings to IDs and declaring sizes up front. I saw something during development around this though.
  • Note that the default value is 0 and when a variable doesn’t change the value, no update will be triggered. Also make sure to hit send on the command in the window, that first Got data: 0 is reading the default/empty state of the client data region.
  • Should prefer sizeof and Marshal.SizeOf for struct sizes, but this makes it clear what is what.
2 Likes

I suggest using the register/set/get variable functions instead, because with execute_calculator code you are unnecessarily forcing the sim to send the expression through the XML evaluator every time, which is not needed if you don’t really need an “expression”, the whole point of this would be that external clients in C++/C# would create their own logic, and they surely could do it so much faster and better and with way more complex logic that the XML expression evaluator could possibly do.

1 Like

Agree, however I didn’t find that “A:LIGHT LANDING” worked. I’ll have to give it another try.

Hello,

another way to interact with local variables is to define a client data section. This has the advantage, that you can specify a certain name for the client data section. Choosing a proper name will ensure you’re not conflicting with any other add-on.

Examples:
a32nx/SimConnectData.h at autopilot · flybywiresim/a32nx (github.com)
a32nx/SimConnectInterface.cpp at autopilot · flybywiresim/a32nx (github.com)
a32nx/SimConnectInterface.cpp at autopilot · flybywiresim/a32nx (github.com)
a32nx/SimConnectInterface.cpp at autopilot · flybywiresim/a32nx (github.com)
a32nx/FlyByWireInterface.cpp at autopilot · flybywiresim/a32nx (github.com)

As you can see, I’m using not only the client data section for local variables, but also others in parallel and different directions (in and out of the sim).

Best,
Andreas

I’ve read trough the topic and I am happy to see the ideas around this advance.
There’s a person who developed some very interesting tools, he also helped me a lot at one point.

Please, take a look at his work, it might be inspiring and certainly helpful.
I’ll point you directly to some of his posts in order to highlight at least a small bit of what it’s all about:

— also:

— additional stuff also useful to me for my project:

All the best,


Milan Putnik
mr.sci.eng.

Hello @VFRMau,

thanks a lot for sharing your ideas and code. This project addresses just what I need.

I built an A320 FCU hardware for FSX and interfaced to the sim by my own gauge project written in C++.

As MSFS came up, I created a C# project which interfaces with MSFS and offers a plugin interface. Up to now, there are plugins for the A320 FCU and for a moving map on Android devices. Unfortunately, the A320 FCU plugin still misses some functionality which is not available in SimConnect right now. An A320 EFIS project had not been started as those functionality is completely unavailable, yet.

Then I saw this project which offers a chance to control even the EFIS. I got the Code from GitHub and started with a C# A320EFIS plugin. But unfortunately, I was not able to get it working. That’s why I ask here for some ideas.

Some facts:

I use C# and the C# simconnect interface.

I map an Event :
_simConnect.MapClientEventToSimEvent(ev.SimIdent, ev.Text)
with ev.SimIdent=1 and ev.Text = “#0x11001” // using array LVAR_EFIS_PANEL

Then I fire events:
_simConnect.TransmitClientEvent(_objectId, ev.SimIdent, ev.Value, GroupId.A320FCU, SIMCONNECT_EVENT_FLAG.DEFAULT);
with
_objectId=1 // my A320
ev.SimIdent=1 // as mapped above, i.e. LVAR_EFIS_PANEL array
ev.Value=0x103 // third array entry=A320_Neo_MFD_Range_1", range 1

Unfortunately, there is no effect visible. The knob is not turning, the range in the ND is not changing.

I tried this with and without the A32xNX mod with the same negative result.

I also tried changing other values from the LVAR_EFIS_PANEL entries, all without success.

Right now I have no idea what to try next. I am not familiar with WASM, so all I did was copying the WASM and its JSONs into the community folder as described.

Has anyone a hint for me?
Is there any chance to tell whether the WASM gets loaded by the sim?

Any help appreciated.

Regards,
Jens

Hi @SpiralCharger,

Thanks for your kind words and I hope my code helps you in building an EFIS module. I’m not familiar with C# syntax, but from the looks if it, the error might be the ev.Text value. Could you verify that the ev.Text also contains the pound (#) sign, it should read (also see the opening post):

ev.Text = "#0x11001";

If that doesn’t solve your problem I can have another look at it.

Good luck trying!

Hi @VFRMau,

indeed the pound sign is there. I tried to copy as much as possible directly out of the debug session. And doing so right now showed me that the double click on the value which I supposed would select the entire value string just selects the value without the pound sign. I did not realized it when writing my previous post, my apologies for the confusion!

Having cleared that, it appears that mapping the event should not be the problem.

Would it be possible to include a logging command in the source code of the WASM so that I could track whether the WASM gets loaded and called?

Thanks for your help!

Check your developer mode console.

Of course, it will help if you place some diagnostic fprintfs in your code, since they’ will also go to the console, when directed to stderr.