Jump to content
The simFlight Network Forums

LUA handling of simultaneous button events


Recommended Posts

When programming a collection of LUA scripts for Manfred Jahns L749, where I wrote a library, that allows full hardware operation of the plane, I hit upon a tricky problem with the occurrence of (almost) simultaneous button events, that comes from the fact that LUA plugins are terminated and restarted by subsequent calls, regardless if they have previously completed or not. By reasons of portability I wanted to have the button and keyboard association by means of FSUIPC rather than hard-coded in the script.

Saitek Aviator Joystick has a rotary switch with three positions (off, A, B) which is orginally used as a mode switch. Nevertheless, positions A and B are simply connected to joystick buttons 12 and 13. In off position neither of the buttons is active. It appeared attractive to use the switch as the structural deice control of the L749 which also has three positions (off, on, extended). The idea was using event 12 for going to "deice on", 13 for "extended mode", and "off" by means of the release of button 12 to go back to "off mode". Obviously the sequence of the events would be important. Therefore the transition to "deice off" was allowed only from the "on" mode but not from "extended". By this, so the idea, it could be achieved, that independent from the sequence, switching to position "B" would reliably result into "extended" mode. Even if the release of 12 wold occur after the down-event of 13, going back to "off" would be blocked, if "extended mode" has already been set. Otherwise, if the release of 12 would occur before the down-event on 13, the deice would go to "off" for short, but immediately return to desired "extended" mode.

Unfortunately, this worked only if I had different LUA-script files for each sub-command, because calling the same script just with different parameters resulted into a premature termination of the running script, ending with the effect that I could not produce the transition to "extended"-mode at all. Instead the position of the virtual know always went back to off-position.

Now, with the 4.645, it turns out to work, because incidentally the release of button 12 occurs slightly after the down-event of 13. The result is that the first call (button down 13) does the transition to the desired "extended" mode. The call of the release event of 12 is not executed at all, because it falls into the 66 ms blanking time. I was lucky, indeed. However there is a substantial risk that the problem reappears wiht other hardware, or after some future software update. Other might have had a similar problem also.

Another problem of the killing of a running script is a high risk that a set of script variables might be left in an inconsistent condition, i.e. there might occur a situation where parts of the variable set refer to some updated situation, while other parts still reflect the original situation, because the script didn't update all of these. As a programmer one has to keep in mind that the script might be interrupted at any time, with all consequences of the variables state.

I would like to suggest to consider a more explicit handling of this situation. I was thinking of some flag that controls if a new call is queued until the previous has completed. Another option might be to allow several instances of the same script, although this might introduce further problems with thread safety (maybe not so a good idea). Another idea could be the introduction of a sort of "critical section", which allows to protect sensitive parts of the code.

best regards,

Peter

Link to comment
Share on other sites

Hi Peter,

I am not sure I fully understood what you were trying to achieve but have you considered a different approach:

Have one Lua script that does it all and that runs in the background listening for your events. Basically it would look like something similar to:

function handleButtons(joynum, button, downup)
  -- check if what number the button is for your joystick
  -- you could debug it by using one of the two
  -- ipc.log("Button mask: " .. button)
  -- ipc.display("Button mask: " .. button)

  if button == <number button 1> then
      ipc.display(button .. " pressed")
  end

  if button == <number button 2> then
      ipc.display(button .. " pressed")
  end

  if button == 0 then
      ipc.display("last button released")
  end


end


-- get the joystick number or the joystick letter from your fsuipc.ini [joynames] section
-- if you use the letter encompass it in ""
event.button(<your joystick number/text>,255,3,"handleButtons")

It is not ideal because you need to know the joystick number and button numbers but it saves you from the trouble of terminating lua scripts.

You do NOT assign this to the buttons but add it to luas being started by FSUIPC (see manual for possibilities).

If you do not have it yet get yourself the FSUIPC SDK Documentation from this forum and read FSUIPC Lua Library.pdf for more information.

Kosta

Link to comment
Share on other sites

When programming a collection of LUA scripts for Manfred Jahns L749, where I wrote a library, that allows full hardware operation of the plane, I hit upon a tricky problem with the occurrence of (almost) simultaneous button events, that comes from the fact that LUA plugins are terminated and restarted by subsequent calls, regardless if they have previously completed or not.

If you call the same Lua script again before the first has terminated there's no alternative -- but an exception is made by button and key repeats which are simply omitted until the Lua in completed UNLESS this takes more than so many miiliseconds.

It sounds to me as if you should consider using an always-running (loaded as or by ipcReady.lua) script which contained functions called by events.

Unfortunately, this worked only if I had different LUA-script files for each sub-command, because calling the same script just with different parameters resulted into a premature termination of the running script, ending with the effect that I could not produce the transition to "extended"-mode at all. Instead the position of the virtual know always went back to off-position.

Apart from using events to program this, you could also just make sure only one button press causes the Lua to run with the others either tested in the Lua, or changing flags for that Lua for it to test.

Or you could have separate smaller Lua scripts and use Global variables to communicate between them.

Another problem of the killing of a running script is a high risk that a set of script variables might be left in an inconsistent condition, i.e. there might occur a situation where parts of the variable set refer to some updated situation, while other parts still reflect the original situation, because the script didn't update all of these. As a programmer one has to keep in mind that the script might be interrupted at any time, with all consequences of the variables state.

If you mean variables declared in the Lua script itself, they are all undefined ("nil") initially. When a Lua plug-in is terminated, it all disappears, so each time it is restarted it is starting afresh. Only Globals have any on-going life as the functions to set and read those store them into space owned by an always-running Lua thread created specifically for the purpose.

I would like to suggest to consider a more explicit handling of this situation. I was thinking of some flag that controls if a new call is queued until the previous has completed. Another option might be to allow several instances of the same script, although this might introduce further problems with thread safety (maybe not so a good idea). Another idea could be the introduction of a sort of "critical section", which allows to protect sensitive parts of the code.

I'd prefer folks to move to event-driven scripts where they are likely to get as complex as you suggest. Kosta has the idea! (Thanks Kosta).

And for simple things like timing a button release, the assignment can call the Lua and the release can set a Lua flag. I've used that as well, where I didn't want to specifically assign the button number in the Lua.

Regards

Pete

Link to comment
Share on other sites

Hi Pete, hi Kosta,

thanks for your extensive and helpful feedback. I think I didn't consider the "flag"-option yet, this could indeed by a solution for the isolated problem with the mode switch.

The reason why I didn't go to the continuously running script (yet) was to keep the possibility to map the commands by means of the FSUIPC user interface. I think this is a great advantage of FSUIPC that you can adapt the function mapping easily to any controls hardware or user preferences.

Actually I started with a bunch of some 20 different scriptfiles, handling a different function each. The functions could have several modes, say "on", triggered by one button, and maybe "off", triggered by some other button, which were adressed by parameters (ipcPARAM). As described above, this didn't work reliably for the mode switch, so for this I had to provide an individual script for each button event.

After all I ended up with more than some 30 scripts populating the modules folder and overcrowding the drop-down list in the FSUIP user interface. So I tried to put it into a single library, plus a sort of dispatcher that navigates the individual events to the appropriate library routines. This what I put recently into the "User Contributions" section of the forum. Because of the 66 ms blanking time this actually works, because of the specific sequence of the button events.

Regarding the variables, I mean of course the globals, created with ipc.set(“name”, value), but also the Lvars, extensively used in custom gauges, and last not least aircraft variables at offsets. I have all the documentation of FSUIPC and the LUA plugins and I make extensive use of it.

While simultaneous pressing of buttons might not be the usual case in standard game controllers, the mode switch of that particular Saitek Aviator Joystick operates two buttons (12 and 13) almost simultaneously when switching from A to B. As these coincident events are occuring at the foremost end of the signal chain, the overlapping execution seems unavoidable, if two conditions are met: 1) You are using FSUIPC to map button events to script files and (highly preferred) 2) Both buttons are mapped to the same script file (obviously with with different parameters, e.g. in case of providing one library for a particular aircraft).

As you wrote (and as I did initially), a solution is having different scriptfiles, which can become pretty messy, if a more complex set of scripts is considered. Basically, this situation suggests, as Kosta said, to realize the button handling (and mapping) entirely in LUA which makes it much more difficult for an average user to adapt a script to his own hardware. And, the fact, that a script may be terminated at any time, requires special attention to the consistency of variable sets.

I'm not yet sure, but after using Guenseli's Catalina-library, I observed occasionally some alteration of the flight dynamics, after using the FSUIPC interface. This might come from such an interrupted routine in the panel system which adjusts the drag and lift poperties by sets of invisible flaps and spoilers, and left inconsistent after an interruption. Might be his problem with the rotary knobs has something to do with this either.

As I said, I don't know what the ideal approach for this problem could be. Another idea might using "virtual control mapping" by FSUIPC, which can be adapted with the user interface, and use a looping script which polls continuously the state of the virtual buttons and axises. This would avoid the killing-problem and keeps the flexibility ease-of-use in the mapping of controls. I know there is already a set of "virtual buttons" for use with external hardware, but I'm not sure if this would be recommended use of it. Anyway it would allow configuration by offset-commands from the user interface. Might be better to have some sort of "user-scratchpad" area in the offset-section.

best regards,

Peter

Link to comment
Share on other sites

The reason why I didn't go to the continuously running script (yet) was to keep the possibility to map the commands by means of the FSUIPC user interface. I think this is a great advantage of FSUIPC that you can adapt the function mapping easily to any controls hardware or user preferences.

Yes, i see that.

The Lua flags are one way, but limited and not global like buttons.

How about an added FS assignable control to simple create an "event", simply a numbered event (the number in the parameter, which can be handled in Lua by an ipc.test function and a new event. function? Then you simply design your Lua with button independence, defining event numbers which can be assigned?

The problem then, of course, is that two persons might design Lua plugins to do worthwhile things which use overlapping event numbers.

Really, the Lua specific Flags (32 of them) were intended to fulfill this function. Is perhaps ythe limit of 32 a problem? I could probably extend that easily enough. 64, 128, 256?

Regards

Pete

Link to comment
Share on other sites

How about an added FS assignable control to simple create an "event", simply a numbered event (the number in the parameter, which can be handled in Lua by an ipc.test function and a new event. function? Then you simply design your Lua with button independence, defining event numbers which can be assigned?

The problem then, of course, is that two persons might design Lua plugins to do worthwhile things which use overlapping event numbers.

I think something like that could be achieved already right now by using the "virtual button" offsets, and indeed, overlapping use would become a problem in any way.

Really, the Lua specific Flags (32 of them) were intended to fulfill this function. Is perhaps ythe limit of 32 a problem? I could probably extend that easily enough. 64, 128, 256?

I think that would solve it 99%. 32 is actually pretty limited, although a workaround could be to have not more than 32 functions in one library. If more are needed, a second library would be used, and so on. Increasing the number would keep the whole thing more elegant, though. Why not 256? This would offer also a some margin for encoding extra information, e.g. selector switch states, more conveniently by flags. And still, hardware configuration by end users is simple, because all what is required is a 1:1 translation table, for mapping flag numbers to the implemented actions.

I cannot find, however, a library call for manipulation of the flags by a Lua script itself. It would be very helpful if there is also the option to clear (and possibly also to set, something like ipc.setflag and ipc.clearflag) a flag by the Lua script, too. This would allow capturing even very short button actions, because there is no need to reset the flag already by releasing a button, if it can be cleared from the Lua script after processing it.

best regards,

Peter

Link to comment
Share on other sites

32 is actually pretty limited, although a workaround could be to have not more than 32 functions in one library. If more are needed, a second library would be used, and so on. Increasing the number would keep the whole thing more elegant, though. Why not 256? This would offer also a some margin for encoding extra information, e.g. selector switch states, more conveniently by flags. And still, hardware configuration by end users is simple, because all what is required is a 1:1 translation table, for mapping flag numbers to the implemented actions.

Okay. I'll look at doing this. Next week though. I have guests here still.

I cannot find, however, a library call for manipulation of the flags by a Lua script itself. It would be very helpful if there is also the option to clear (and possibly also to set, something like ipc.setflag and ipc.clearflag) a flag by the Lua script, too. This would allow capturing even very short button actions, because there is no need to reset the flag already by releasing a button, if it can be cleared from the Lua script after processing it.

Yes, that all makes sense.

Regards

Pete

Link to comment
Share on other sites

... Increasing the number would keep the whole thing more elegant, though. Why not 256? This would offer also a some margin for encoding extra information, e.g. selector switch states, more conveniently by flags. And still, hardware configuration by end users is simple, because all what is required is a 1:1 translation table, for mapping flag numbers to the implemented actions.

I cannot find, however, a library call for manipulation of the flags by a Lua script itself. It would be very helpful if there is also the option to clear (and possibly also to set, something like ipc.setflag and ipc.clearflag) a flag by the Lua script, too. This would allow capturing even very short button actions, because there is no need to reset the flag already by releasing a button, if it can be cleared from the Lua script after processing it.

The latest interim versions of FSUIPC, 3.989u and 4.647, feature 256 flags per Lua plug-in, and extra ipc library functions to set, clear and toggle them individually.

I should point out, though, that the solution to your specific problem, i.e.

This would allow capturing even very short button actions, because there is no need to reset the flag already by releasing a button, if it can be cleared from the Lua script after processing it

would surely have been to use "luaToggle" to change the flag rather than set it or clear it specifically? The event.flag function detects any change.

Regards

Pete

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use. Guidelines Privacy Policy We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.