Reading Simultaneous Button Presses

Support for Arduino in combination with Air Manager and Air Player

Moderators: russ, Ralph

Message
Author
User avatar
jph
Posts: 2846
Joined: Fri Apr 10, 2020 12:50 pm
Location: Somewhere over the rainbow..

Re: Reading Simultaneous Button Presses

#11 Post by jph »

Hi @bdcurry
@Sling Sling (Tony) is spot on. (as usual ;) ), and Tony, I would be really interested to have your input, or indeed, any of the very experienced LUA / AM programmers (of which I am not) - Jacques, Keith and others of course - .
I do have a lot of programming experience, but definitely not in AM. / LUA although I have a good working knowledge of what AM and LUA can do, but am sorting my hardware out first and I know it will work either with AM programmed Arduinos, or via message port or via a combination with custom Arduino / custom hardware + LUA /AM + Custom HID etc - so either way it will be no worries.

There was something that I mentioned in my first post though - that is "You may have to consider precedence of actions". My suggested use of an OR gate is / was an exercise in an option for what could be done in hardware on a very cheap basis allowing for any constraints of the AM programmed Arduino in AM. It may well be a great option, but perhaps not in this case. Either way, it is a definite tool to have in your box of tricks and the implications for what can be done are enormous.
What I mean by this is that the code in AM may have to consider in which order the buttons are pressed and which actions to take depending on the instrument and usage.

As pressing both buttons simultaneously wont actually be totally simultaneous, then you may well need to allow for the actions that may, without appropriate coding, be taken on the first button press detected prior to the second button press being detected even though they are only a fraction of a second apart. In a case of a scenario such as yours, the action of the third button press function call (even if an individual button press call is executed first) will happen no matter what actions may have been taken by either button press being captured first as in this case a reset is what you want, hence it doesn't matter what a prior individual button capture event does.

From other programming experience I have, I believe it would go something like this :?: (to slightly expand on Tony's comments).
Taking an input scenario with 2 buttons (all in AM) with both single individual button presses being required to be registered for each individual button function, and also a dual press of both buttons to be registered to activate a third option then -
In each button press function call, a flag is set to indicate the button has been pressed. The flag is reset (cleared) on the button release function in AM.
On a button press function call, presuming the button is still pressed, hence not yet released, the specific button activated flag will still be set. The code then also inspects the second button for an activation flag (prior to doing anything else) - and visa versa. If - after a certain time (which can be used as de-bounce as well) the 'other' button flag is not set, then the individual button press function occurs, the button release function resets (clears the flag). If both flags are seen as set the virtual 'third' button option is activated. In this theoretical scenario, then the single button press(es) - and their normal actions within the function will effectively be ignored if the second button press is within a time window (set by the de-bounce or delay routine), and only the virtual third button action will be taken. No de-bounce needed on the virtual third button as it is only done in code.

Again , thinking out loud, (dangerous) ;)

The gurus will hopefully step in and comment and suggest far better options if I am way off mark.

and, @bdcurry , keep looking and considering the logic gates and Boolean functions as they can also have a massive impact on both hardware and coding as the same logic can be, and is often used within code.
best regards, Joe.
Joe. CISSP, MSc.

bdcurry
Posts: 20
Joined: Tue Feb 16, 2021 1:28 am

Re: Reading Simultaneous Button Presses

#12 Post by bdcurry »

Thanks Joe and Tony -- good stuff to work through and I'll keep considering the logic gates and Boolean operations. I agree with your logic flow, Joe. As I think through it and with the reality that it's physically impossible to get both push buttons pressed at exactly the same time, the mode of the timer and in what sequence those two buttons on the chrono (function and control) are pushed is important. In the timer mode, pressing the control button starts/stops the timer. I could see "manually" ensuring the order by selecting the timer mode, and then ensuring that the control button is pushed first (start/stop) and then the function button to perform the reset function. I believe in any other mode, the simultaneous button press has no function. Coding all of that will be a struggle for me given my skill level but logically it makes sense. I'll start digging through the resources to see what I can put together on the code side. I've order some of the OR gate chips and will start prototyping. Again, I appreciate the assistance and if anything else comes to mind, I'd be interested to read it.
Best Regards, Brian

User avatar
Sling
Posts: 5237
Joined: Mon Sep 11, 2017 2:37 pm
Contact:

Re: Reading Simultaneous Button Presses

#13 Post by Sling »

The easiest way to control the use of the buttons for their main function is to only do the main function on release. With a normal button press the operation from the users perspective is the same but in the code it makes it so much easier to manage. Down the years ’ve come across several systems that use the release and not the press as the trigger action so it’s used already.

Just an idea.

ChuckK
Posts: 95
Joined: Sun Nov 06, 2016 2:33 pm

Re: Reading Simultaneous Button Presses

#14 Post by ChuckK »

Tony’s M803 indeed works perfect with the functions called on the button release. A great free instrument to look at is the JPI700. It uses a timing function to add long button presses to the logic. I’ve made quite a few upgrades to this instrument that utilizing single and dual presses and releases. The built in functionality is enough to perfectly replicate JPI700 POH

Chuck

bdcurry
Posts: 20
Joined: Tue Feb 16, 2021 1:28 am

Re: Reading Simultaneous Button Presses

#15 Post by bdcurry »

Thanks, I'll take a look at the JPI700. It makes sense to use the button_release but wouldn't that have the same issue as button_pressed -- both won't be released at exactly the same time. I'm guessing that the JPI700 will provide insight into how that's handled so I'll start there. One thing that confuses me is creating a nested function or defining the two buttons and then getting the two callback functions to be usable outside of each function group (sorry, I'm sure I'm mangling code nomenclature). Maybe declaring a global value for each press/release state and then doing the logic to execute the desire command will accomplish that. Anyway, thanks again for the input and I'll start with the JPI700 reference.

User avatar
Sling
Posts: 5237
Joined: Mon Sep 11, 2017 2:37 pm
Contact:

Re: Reading Simultaneous Button Presses

#16 Post by Sling »

bdcurry,

I’m not sure you follow. The both logic is done in the press callback but the main button functions namely SEL and CTRL are handled in the release callback. One button being pushed slightly before the other becomes a non issue because the main action is only actioned on release.

User avatar
jph
Posts: 2846
Joined: Fri Apr 10, 2020 12:50 pm
Location: Somewhere over the rainbow..

Re: Reading Simultaneous Button Presses

#17 Post by jph »

To add to the above Brian, a possible scenario to help explain possibilites.
The use of the 'release' function - as well as the 'pressed' function allows an appropriate use of 'flags'
In this case, a 'flag' that I refer to is either a variable being set that is used to signify an event has happened, or - any method to 'set' something to a state that can be read by another function for the duration you want to. In most programming languages you can simply set a 'bit' of a byte to use a flag, but I don't know LUA very well. It is basically ANY method of applying a signal of some sort for the duration that you need.
If you take a normal 'pressed' function, then if you want to set a 'flag' to indicate the action is in use for another function to be able to read that, then you need some method of 'clearing' the flag when you have accomplished the intended reason for 'setting the flag' - if that makes sense ?
Take a situation where the two button press detection is used. This is an ideal case for 'flag' setting. If a button is pressed normally and then released, but, is also expected to be, at some time used in a dual press action with another button, then setting flags is good. If you press one button with the intent of another button being pressed for the case of registering a dual press scenario then the press of the second button could need to see a 'flag' that the first button has been pressed and held - or visa versa - second button first, held, followed by first button.
Hopefully, you can see that the use of the 'flag' during each press, whilst pressed, is a method of being able to check the condition of each button state to enable a dual button press / held action.
In this case, then the flag needs to be maintained throughout the button pressed and held for the duration of the 'pressed' event.
But we also need to know when to clear the flag in the event of a 'normal' button press, or indeed, a dual button press - as this could be the only reason to use the 'flag' in these routines.
In this case, the ideal way to clear the flag is ONLY when the button press event of any button involved is finished with - hence - use the 'button release' ability of AM to clear this flag.
There are of course other cases where this method is useful and appropriate, but in the context of our dual button press initiating a third action this a good example of how to set a 'flag' - on button press and then ONLY reset / clear the 'flag' on button release.
Hope that helps ?
Joe
ps =
It is still definitely great that you ordered a few or gates. Maybe get yourself a selection of logic gates (use 74HCXXx) - not 4000 series or 74HCT. You will have great fun with a bit of bread board, a few switches . buttons and a few leds and may well decide you want to use that method for the dual press, or at least compare. Either way it gives you loads of option in both hardware AND code. - get a few AND, XOR, NOR etc.
Any of the main blocks that are cheap so you can play. ;)
Joe.
Joe. CISSP, MSc.

bdcurry
Posts: 20
Joined: Tue Feb 16, 2021 1:28 am

Re: Reading Simultaneous Button Presses

#18 Post by bdcurry »

Thanks again for all the input. Tony -- yeah, I'd say I might be missing the logic or how the press callback differs from the release callback (in time). Certainly it's a struggle for me to get that down into code form given my skill level and that hampers me frequently when working on different aspects of the sim hardware. Joe -- might be that I'm missing the application of flags to the press/release callback event. I understand the concept of setting flags but again, getting that into code is where it slows down. I'll setup a basic two button instrument and focus on the logic, flags and actions using the press/release callback. I'll need to get better at coding logic (if, or, and, else, not,....) -- any online resources you guys would recommend to learn the coding aspect? As far ad the gate chips, I just find that interesting and will enjoy what that brings to the table.

User avatar
jph
Posts: 2846
Joined: Fri Apr 10, 2020 12:50 pm
Location: Somewhere over the rainbow..

Re: Reading Simultaneous Button Presses

#19 Post by jph »

Hey Brian,

Not a direct answer to
I'll need to get better at coding logic (if, or, and, else, not,....) -- any online resources you guys would recommend to learn the coding aspect?
-as a not online exercise - just a bit of thought provocation out of my tiny head - here is a small sample as there is so much to learn with regards to Boolean logic.

Regarding flags etc. Flags are simply a temporary means of storing any kind of signal that you can refer to to see if an action has occurred. We can come back to them later.... No worries. You asked, so thou willst receive haha :P

Again, just for sh!ts and giggles, to offer a completely, random - but hopefully thought provoking approach to how the logic gates and Boolean logic can also apply to coding - which is a mainstay of coding.
Let's try to create a really simple version of a RAID array in RAID 5. (striping with parity - simplified)

Yes, this is completely out of the ball park ;) but I am only using it as an example as to what can be done and how, sometimes, the difficult can be so easy using logic. Get a piece of paper if needed and see it in action. All you need is an XOR truth table, which is your OR truth table but made exclusively (X) by only being true (1) if the inputs are different to each other. -you can find an XOR truth table on line.
I am simply offering this up as an example of a differing Boolean approach and to see the result s- in hardware - or software. it is sometimes easier to look at something different then go back to the original.
Let's presume we have 3 drives and 2 byte values are stored on the drives 1 and 2.
The third drive (3) has a byte that is derived from the XOR result of the bytes on each of the primary two drives. Let us call the 3rd drive the 'parity' drive.
So, drive 3 contains the result of DRIVE1 XOR with DRIVE2.
Now, in the case of loss of either drive 1 or drive 2, then the data is still available ! - how ? because the XOR result of the first 2 drives is written to the 3rd - parity drive. and can be used by to calculate either drive 1 or drive 2 value as shall be seen. - It is fault tolerant. one simple XOR of two byte values gives a result that can be used to recreate either original value. HOW ? :shock:

An example.

Drive 1, byte ---- 10101001
Drive 2, byte ---- 00011100

Drive 3 = XOR result of drive 1 XOR drive 2

= XOR
10101001 (drive 1)
00011100 (drive 2)
=
10110101 (result of drive 1 XOR drive 2) (confirm this with the XOR truth table) this is stored on drive 3

So, in the event of drive 2 failing, we have drive 1
10101001

and the parity drive result of
10110101

So, if we now XOR the 2 remaining values -- drive 1 XOR parity drive (drive 3) we get
10101001 (drive 1)
10110101 Drive 3 Parity drive)

= XOR result of the above)
00011100 which = the 'lost' drive 2 value.. !

It also works for drive 1 failure.. try it out .

You can use any single drive 1 or drive 2 failure and 'remake' the original value of the 'lost / failed' drive from the 'parity value stored on drive 3 with XOR.
Once you have the initial values for drives 1, 2 and 3 - you can fail any one drive and recreate the lost value by an XOR of the remaining 2 values. - obviously in the case of the failure of the drive 3 'parity' drive there is no need to 'recreate' the value as nothing is lost.

I am not trying to complicate things - and we can come back to flags later, I am just giving an example of what appears to be a complex scenario that is absolutely - and seemingly magically - yet so beautifully simple with the Boolean logic applied .

when you go back to the OR it will apear trivial. (hopefully) ;)
Joe. CISSP, MSc.

bdcurry
Posts: 20
Joined: Tue Feb 16, 2021 1:28 am

Re: Reading Simultaneous Button Presses

#20 Post by bdcurry »

Joe -- I think my head just exploded....... :shock:

That's going to take some doing to understand that. I'll check out truth tables and see if that brings enlightenment. I tried the flag approach as best I could understand it and attempted, poorly, to code that in a simple routine shown below. Obviously this yielded no results with the "both buttons pressed" never being printed. I've found a few free online tutorials on LUA that seem good and have started working through those. I'm still missing something here so I'll keep working at it. Any breadcrumbs appreciated and thanks for the time to write that up.

flag1 = 0
flag2 = 0

function button1_pressed()
print ("vs button 1 pressed")
flag1 = 1
print (flag1)
end

function button2_pressed()
print ("vs button 2 pressed")
flag2 = 1
print (flag2)
end

if flag1 == 1 and flag2 == 1 then print ("both buttons pressed")
end

hw_button_add("ARDUINO_MEGA2560_<A>_D38", button1_pressed)
hw_button_add("ARDUINO_MEGA2560_<A>_D39", button2_pressed)

Post Reply