Demo: LVAR write access for any aircraft control

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.

Hi Maurice,
sorry for the delay in this. been busy, as I’m sure we all are…
I now have a WASM module that can list and update lvars, as well as activating hvars, with the results being sent to the client via Client Data areas to my test client. The last piece of the jigsaw puzzle I’m interested in now is how to know what lvars and hvars are actually available? I’m currently using pre-defined config files for the lvar/hvar names. Is there a way to determine what lvars and hvars are available for the current loaded a/c via code in a WASM module?
Thought I’d post here, but maybe this needs separate topic…

John

Hi John-

I haven’t worked out a way to list available h-events, but you can get the available Lvars by using:

PCSTRINGZ get_name_of_named_variable( ID  id );

The function returns the name of the lvar for a given ID, or NULL if the lvar ID doesn’t exist.

To see all of the lvars for a loaded aircraft, I start at zero and increment the id until get_name_of_named_variable() returns NULL.

The following will print each lvar to the console for the currently loaded aircraft :

  	bool isValidLVAR = true;
  	int x = 0;

  	do
  	{
  		PCSTRINGZ lvarname = get_name_of_named_variable(x);
  		if (lvarname)
  		{
  			fprintf(stderr, "LVAR ID: %d     LVAR Name: %s\n", x, lvarname);
  		}
  		else
  		{
  			fprintf(stderr, "LVAR ID: %d     no Lvar", x);
  			isValidLVAR = false;
  		}
  		x++;
  	} while (isValidLVAR);

Hope this helps.

Matt

1 Like

Just searching through the code for the aircraft is probably the most thorough way to do so. I know the ModelBehaviors dev menu lists L:vars, but not H:vars. Do you have your code uploaded to GitHub?

@The727Pilot Thanks. Yes, thats a useful method to generate a list of available lvars.
@Iceman2152798 No code in GitHub, sorry. I use AzireDevops and its not public (as commercial).

Gotcha. So then would it be possible for the code to be uploaded to GitHub separately? I’m sure everyone reading this thread would greatly benefit from it - I know for a fact that us at FlyByWire (and the Working Title folks as well) are looking into the best way to get/set Lvars from SimConnect, and if someone already has a robust solution, I see no reason to reinvent the wheel here.

Ok. I’m still working on it. I’ll consider putting the WASM module into GitHub when done. But this is still several weeks away - unfortunately I’m not getting enoght time as I’d like to work on this at the moment…
Note also that there are various different approaches you can take. In my implementation, the client holds a table of all lvars and values, and so reads of lvars are just client side. Values in the table are updated (from the Client Data Areas) at a configurable rate on request from the client (simconnect) and update of lvars on a gauge event.
Change of aircraft and Client Data Area (CDA) size limit (8k) is also a bit of a pain. Changing aircraft means dropping existing lvars/CDAs and re-creating. And the 8k limit on CDA size mean that there is a limit to the number of lvars that each CDA can hold (currently 128 in my implementation, limited by the size of the lvar name, for which I’m currently allowing 56 Bytes), so I’m allowing multiple CDAs per a/c. Not sure if this is necessary though…if 128 is enough (or if I can reduce the 56 byres allowed for the lvar name), then I could simplify the implementation quite a bit.

Just an update concerning my efforts to get the code of @VFRMau working:

Running out of ideas what might be wrong, I decided to create my own WASM module. Doing sowas much easier than I thought and I got it running in 15 minutes. Then, I copied/pasted VFRMau’s code into my own WASM and debugged it.

Surprisingly, the WASM seems to work, even setting a breakpoint at the start of EventHandler() worked. But I never got a breakpoint to be hit in the cases of the switch statement, so I think for some reason transmitting the event does not work.

One general question: Although setting brewakpoints seems to work, I couldn’t watch any variable value. E.g. when breaking at the start of EventHandler(), I tried to look at the value of the function’s parameters. This did not work, neither with “watch” nor with showing “locals”. Is this a limitation when debugging WASM or is this a hint that there is something wrong with the project properties (e.g. calling convention)?

Thanks a lot,
Jens

Guys, I think we should really need to talk about this situation:

Everybody here seems to be in the process of reinventing his own version of the wheel: getting some access to LVariables via Simconnect communication with WASM, because Simconnect doesn’t allow to do that directly.

The result of this, is that in a very short time, we’ll have multiple modules running all at the same time, doing the same thing, increasing traffic over the named pipes used by the several Simconnect clients to talk to each other, to the detriment of everybody’s performances.

Yes, of course, we already have our own WASM module that does the same thing, and it’s hard enough being careful to optimize it as best as we can to reduce unnecessarily traffic without being worried by dozen of other identical modules doing the same service.

So, I think we REALLY need some kind of coordination here, unless you think it’s possible to lobby Asobo to add direct LVar/Hvar acces to Simconnect proper.

Is anybody willing to start a joined project on Github, which can be contributed by all interested developers, that can be distributed as a SINGLE, separate package, with every product that requires it ?

Note that, we already have our own WASM module fully working right now, with only the things we need, but of course the whole concept of using Simconnect itself as a communication channel between WASM and external EXE can be easily expanded to provide further services. There are some things that need to be handled with care, one for example is the synchronization between requests, which you might not notice if you “just” want to read or write an LVar, but will become obvious if you try to do things very fast from the client side. Yes, we handled this too in our module.

Also, to really make it work, we should try to stick with it and use it, and enhance it, instead of “just” taking the source code and make a fork of it to create a separate version, because that would defeat the purpose of having a single module installed in the sim at any time.

And, we would require some clarification and possibly some support from Asobo about how Dependencies will eventually work, in case multiple products using the module would work on the MS Marketplace, and possibly the Xbox version too. Who’s going to send the the MS Marketplace team the latest version of the module ? How fast can be kept updated ?

So yes, I understand there are tricky issues to be solved first and, if you think about it, the situation in FSX/P3D wasn’t that different, since even there you couldn’t access LVar directly without using a .DLL but, maybe, we have a chance to makes things better now.

Because, the LAST thing we want, is that in a year, there will be dozen of apps on the MS Marketplace, each one installing its own version of a WASM “bridge” ( that’s how we call our version ), clobbering the sim and the Simconnect communication channel for everybody, and this assuming all modules are done equally well and won’t crash the sim or conflict with each other.

8 Likes

Well said Umberto, documentation is key I think as well as the implementation of LVar and HVar in Simconnect that link with WASM Module.

1 Like

I believe the best way forward here is to put pressure on MS/ASOBO to implement a generic WASm bridge to allow direct SimConnect read/write to standard SimConnect Event and Variables as well as
(>H: Events and LVars. Without MS/ASOBO involvement here, it is going to be a mess.

I have now 4 “WASM bridges” active for SimConnect Client App, but would very much like to have just one.