Demo: LVAR write access for any aircraft control

I read this topic with great interest and agree with the statements that Asobo should coordinate access to and from all sim variables. Is there a request that I can upvote? (every single vote may count). Since Asobo/Microsoft everytime mention they want to provide a platform, this kind of infrastructure should be on top of their list.

I do understand that their hand are tight to the FSX/SimConnect/LVar structure, but they could peek at the X-Plane dataref/command solution that boosts the X-Plane ecosystem.

1 Like

I’ve stumbled on this topic by accident! And when I see the technique shown in this topic, it is exactly illustrating one the problem I try to explain: the user customer event are useless, because as soon as you mix 2 add-ons you take the risk both are using the same events, because these are just numbers!

Like you’re saying, there is a lot to learn from the X-Plane SDK. Don’t tell me, I’ve been telling for months
 It is a one way communication channel only though.

Not really. Events can be either strings or numeric IDs. A simulator default event is usually a name (even if it has an ID as well ), but you can create custom event using a string:

SimConnect_MapClientEventToSimEvent( hSimconnect, EVENT_ID, “My.Event.Name” )

The EVENT_ID on the 2nd parameter it’s only relevant to the client, it can be 0, 1, 2, 3, etc ( they are usually like this, because are listed inside an Enum that starts from 0 ), what matters to the sim is the 3rd one, which is a string in this case.

Quoting from the SDK:

If the event name includes one or more periods (such as “Custom.Event” in the example below) then they are custom events specified by the client, and will only be recognized by another client (and not Microsoft Flight Simulator) that has been coded to receive such events.

So, in our version of the reinvented wheel, which we had to reinvent like everybody is doing too, because there’s no way to access L: and H: vars or fire up executeCalculator code from SImconnect, we did something like this, in this case the “Register Variable” command:

SimConnect_MapClientEventToSimEvent(g_hSimConnect, EVENT_WASM_API_REGISTER_VARIABLE_QUERY, "WASM.RegisterVariableQuery");
SimConnect_MapClientEventToSimEvent(g_hSimConnect, EVENT_WASM_API_REGISTER_VARIABLE_RESPONSE, "WASM.RegisterVariableResponse");

These are used BOTH in the Server ( WASM module ) and the Client ( regular EXE ), just they use their client data areas reversed, what is “Input” for one is “Output” for the other.

Now, suppose the .EXE client wants to Register a new L: variable, it will use SimConnect_TransmitClientEvent, with the EVENT_WASM_API_REGISTER_VARIABLE_QUERY, which will send to the sim the “WASM.RegisterVariableQuery” custom event.

The server is waiting its own EVENT_WASM_API_REGISTER_VARIABLE_QUERY id, but what is really waiting for is the “WASM.RegisterVariableQuery” event from the Simconnect pipe, the id can be anything, it only matters to the client.

When the server receives the event, it will do the actual register_named_variable() call ( it can, because it’s a WASM module ), and will do a SimConnect_TransmitClientEvent with EVENT_WASM_API_REGISTER_VARIABLE_RESPONSE which, again, can be anything, what really matters is that is in fact transmitting the “WASM.RegisterVariableResponse” custom event name.

The client is waiting its own EVENT_WASM_API_REGISTER_VARIABLE_RESPONSE, but what is really waiting for is the “WASM.RegisterVariableResponse”, and when it gets it, it will read from the shared client area what has been setup the id of the L: variable which has been associated to the newly registered L: var ( or an existing id, if it was already defined )

This id will be used in the future by the Client, to Write or Read data, using a similar communication methods named “WASM.GetVariableQuery” and “WASM.GetVariableQuery” to READ an L: variable, or “WASM.SetVariableQuery” and “WASM.SetVariableResponse” to WRITE an L:Variable.

So no, it’s entirely possible to create custom events with low risk of name clashing, as long the event names are unique, it’s a method we have been using for quite some time, the SODE ↔ GSX communication API works like this, for example, and so does our new WASM module that will be used by GSX for MSFS to do all sort of things related to using L: or H: variables or calling execute_calculator_code when needed.

1 Like

@Umberto67 Thank you for the explanation, this one is fine and well understood by me, I’ve no problem with.

My post was related to the OP method:
msfs-wasm-lvar-access/src/lvar-access.cpp at main · markrielaart/msfs-wasm-lvar-access · GitHub

// Define the SimConnect custom eventHandler.
static void FSAPI EventHandler(ID32 event, UINT32 evdata, PVOID userdata) {
	// Any event number from 0x11000 through 0x1FFFF is available, but might collide with other mods.
	switch (event) {
	case 0x11000: {
		// Press MCDU button DIR
		execute_calculator_code(MCDU_BUTTONS[evdata], nullptr, nullptr, nullptr);
		break;
	}
	case 0x11001: {
		// EFIS Panel modes
		UINT8 LVAR_INDEX = (evdata & 0xFF);
		ID idA320 = check_named_variable(LVAR_EFIS_PANEL[LVAR_INDEX]);
		// Set a value
		FLOAT64 LVAR_VALUE = (evdata & 0xFF00) >> 8;
		set_named_variable_value(idA320, LVAR_VALUE);
		break;
	}
	}
}

These are the one I’m saying can’t be used reliably because any other gauge could be using the same ID:

// Any event number from 0x11000 through 0x1FFFF is available, but might collide with other mods.

There is one difference between the EventHandler callback and the SimConnect callback is the former was guaranteed to be called synchronously with the event (from FS9 to P3D5), the latter is not and depends on Simconnect (it may, but I can’t find the documentation explicitly confirming this).

Otherwise for the rest, I agree with you and it is no different than X-Plane. Both are making possible using named variables and named events (datarefs and commands in X-Plane):

But there is a twist which is important to me, but maybe only me:

Here are a few of these differences pertaining to “events” (this topic):

  • X-Plane is also offering the SDK/API to intercept and filter commands. You can intercept any command, yours or otherwise, and filter them out, or let them passing through.

  • X-Plane SDK is also implicitly (by example) and explicitly (by documentation) enticing 3rd party to use a standardized naming convention in order to avoid similarly named datarefs and commands, and in order to help categorizing these by the virtue of a path-like prefix. This helps a lot preventing clashes and this also helps a lot customers finding out what command is which (see below).

  • X-Plane is also data driven in the sense any 3rd party runtime created named command can be use in the GUI exactly like its own internal named commands. This makes it very easy for 3rd party vendors to publish their own set of commands and have them bindable in the Joystick config UI for example.

That code is a bit confusing, since the comment says to have defined a “Simconnect custom eventHandler”, which is not what is doing. That’s a plain old school Event handler made with the GAUGES API, which has been moved to WASM now, and it doesn’t have anything to do with Simconnect or Simconnect custom events.

Of course they can clash but, you should see this approach in the context of how this kind of handlers has been used, historically: in gauges of the one and only airplane that can be loaded by the user at any given time. Sure, nobody prevented someone writing a .DLL module that is always loaded to define a custom handler that might use these event IDs and conflict with any other module or gauge, but that’s precisely the reason why it would be best to use Simconnect custom named events INSTEAD!

Everything is inherently asynchronous in Simconnect, that’s how it has been designed (although later P3D SDKs have introduced several new calls to work synchronously), and for the most part it’s better that way, considering it must work both in and out process and potentially even over a network.

And yes, we had to add extra code in our version of the module to have the whole Simconnect-as-a-transport method explained above working synchronously.

For example, since the client might need to register (or read or write ) 30-40 LVariables in a tight loop, it had to use Mutex to be sure a query and its reply has been processed before sending the next one.

It’s not a problem if you just want to use a single variable but, for example, if you want to animate something by using LVars, it’s imperative to work synchronously, otherwise it’s very likely commands will overlap and be lost.

You can do that with Simconnect as well. Event masking.

This is really more like a documentation thing, rather than a design thing. Once you have the ability to define custom events by name, it’s up to developers to come up with sensible names. But yes, I agree the documentation should be more forthcoming about best practices.

This seem to be the main point where I can surely say X-Plane here is better, since it would be really nice if we could define custom events that would be treated just like any other event, especially in the simulator UI.

As of today, even events that WORK in default airplanes, for example the commands to open doors, are not exposed in the UI, so there’s no way to bind them to anything, unless an add-on is doing that , with its own specific UI which would include such missing commands.

So yes, in this case, MSFS ( which is no different than FSX or P3D ), is lacking.

1 Like

Thank you for the reminder on event masking!

I forgot they were also there in FS2020. Otherwise I believe there are pros and cons about async/sync and actually having both is much better for the cases you’d need one instead of the other. I don’t have any typical example I’d cite right now but I have no doubt there are some.

thanks, this is one of the most useful threads ever for me. I’m just pulling it together in VS and will have questions for sure 
 I’m fluent in C#, C C++ so if I can heip anyone let me know 

thanks again

FYI - You can make a project public in DevOps via Project Settings:

It’s all quite straightforward to import a DevOps project into GitHub:
image

It’s good that it was pointed out somewhere around post 80/85 that indeed, the original method that I introduced in the opening post may (most likely will) at some point clash with other developers’ code. For me it’s not that much of an issue, I maintain my private code base and am flexible in renumbering when the need may arise. However, for developers who are looking to use the 0x11000 range for distributed products, this is not the way to go. Thanks for pointing that out more detailed above.

Let’s hope at some stage Asobo will implement a more generic method for us to work with.

Best,
Maurice

1 Like

Is it just me or did anyone else have this stop working with MSFS update to 1.15.7.0?

I am not familiar at all with “WASM development”, so I cannot judge whether this might be related, but there was just an announcement related to WASM modules here:

  • WASM stand alone modules used in some add-ons are no longer working

Thanks for the information! Hopefully, that will fix it.

That was quick:

I’ve only just discovered this, been looking for a way to do this for a while.

Many, many thanks for sharing.

@VFRMau thank you very much for your explanation and your code. I would have never dared to start on something like WASM if you didn’t get me started. Your Github is not ideal but that is maybe even better to get my programming skills up.

@MobiFlight I started with Mobiflight, but because I wasn’t able to get my MIDI encoder knobs to function the way I liked (with vJoy), I started to study your WASM module. I wasn’t able to find out how to connect to your WASM module. Frustrated I gave up and started to study VFRMau’s code. I made my own WASM module and client so I could use my MIDI controller! Very happy but still a bit frustrated I couldn’t use yours. I looked into it again and with new gained knowledge, I figured it out! Thank you very much for putting your code on Github! rtMIDI is a good open source API hint hint wink wink
:wink:

@Umberto67 I agree it would be nice if Asobo would make the sim a little bit more accessible. fingers crossed :slight_smile:

Thanks for your kind words, great hearing that this code is proving useful from time to time.

Best,
Maurice

Yes it is super!

what did you come to understand so you could use it, I’ve not gotten it to work

I am in no way an expert
 but it was easier that I thought (after lot of trial and error). This is the core


void SendToSim(int IDadd, std::string idVar)
{
    hr = SimConnect_MapClientEventToSimEvent(hSimConnect, WASM_EVENT+IDadd, _strdup(idVar.c_str()));
    hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUP_A, WASM_EVENT + IDadd);
    hr = SimConnect_SetNotificationGroupPriority(hSimConnect, GROUP_A, SIMCONNECT_GROUP_PRIORITY_HIGHEST);
    SimConnect_TransmitClientEvent(hSimConnect, objectID, WASM_EVENT + IDadd, 0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
}

Looks familiar, does it not?

this is my functioncall

SendToSim(26, "mobiflight.AS1000_MFD_ENT_Push");
So IDadd has to be different for every event. and I have not noticed but I think it can mingle with other plug-ins. I used 1 to 50 for my events. I have no other add-ons in my community folder.

You first have to set it up with a Handle and some enums and the connection like

hr = SUCCEEDED(SimConnect_Open(&hSimConnect, "--- Begin Send Event ---", NULL, 0, 0, 0));
but how this is done can be found everywhere because it is standard simconnect stuff.

So the most important things;
the simconnect_client_event_id has to be something (different for every event) and the
const char " EventName = " has to start with mobiflight. Everything simconnect does not recognize is interpreted by the mobiflight module
 translated and send again to simconnect.

If you install mobiflight with the wasm module you can find an event.txt in de module directory in the community directory containing all possibilities added so far. On the website hubhop.mobiflight.com you can maybe find more or in an easier fashion.

This is only the event send part. I still have to find out how to get variables.

Hope this helps.

1 Like