-1

I have this programm that has 4 buttons (5,6,13,19) linked to the handleBtnPress callback function. The handleBtnPress function sets a busy flag, prints which button is pressed and then calls the main function which would do some work (in this dummy program, there is just a 5 second sleep) and then releases the busy flag.

import RPi.GPIO as GPIO
from time import sleep
from signal import pause
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
flag=False
try:
    def main_function(button):
        global flag
        print("The main function is called from %s. sleeping for 5s"%button)
        sleep(5)
        print("slept for 5s from %s"%button)
        print("flag released")
        flag=False
        
        
    def handleBtnPress(pinNum):   
            global flag
            if flag!=False:
                print("Waiting for action from %s to finish!"%flag)
                return
            switcher = {
                5: "Button 1",
                6: "Button 2",
                13: "Button 3",
                19: "Button 4"
            }
            flag=switcher.get(pinNum)
            print("flag set")
            print(switcher.get(pinNum)+" pressed")
            main_function(switcher.get(pinNum))
            return
            



    GPIO.setup(5, GPIO.IN, GPIO.PUD_UP)
    GPIO.setup(6, GPIO.IN, GPIO.PUD_UP)
    GPIO.setup(13, GPIO.IN, GPIO.PUD_UP)
    GPIO.setup(19, GPIO.IN, GPIO.PUD_UP)
    
    GPIO.add_event_detect(5, GPIO.FALLING, handleBtnPress,bouncetime=300)
    GPIO.add_event_detect(6, GPIO.FALLING, handleBtnPress,bouncetime=300)
    GPIO.add_event_detect(13, GPIO.FALLING, handleBtnPress,bouncetime=300)
    GPIO.add_event_detect(19, GPIO.FALLING, handleBtnPress,bouncetime=300)

    pause()
except KeyboardInterrupt:
    GPIO.cleanup()

The output I would expect is that when I press the buttons 5,6,13,19 in quick succession (faster than 1sec), the button presses 6,13,19 are ignored, since the busy flag is still set and the 5sec sleep in the main_function is still running. Indeed, I sometimes get this program behavior.

flag set
Button 1 pressed
The main function is called from Button 1. sleeping for 5s
Waiting for action from Button 1 to finish!
Waiting for action from Button 1 to finish!
Waiting for action from Button 1 to finish!
slept for 5s from Button 1
flag released

However, sometimes the program behaves differently and I get the following output, when pressing the button 5,6,13,19 in quick succession (faster than 1sec):

flag set
Button 1 pressed
The main function is called from Button 1. sleeping for 5s
slept for 5s from Button 1
flag released
flag set
Button 2 pressed
The main function is called from Button 2. sleeping for 5s
slept for 5s from Button 2
flag released
flag set
Button 3 pressed
The main function is called from Button 3. sleeping for 5s
slept for 5s from Button 3
flag released
flag set
Button 4 pressed
The main function is called from Button 4. sleeping for 5s
slept for 5s from Button 4
flag released

Once the 5sec from Button 1 press finishes, it instantly starts the 5sec sleep from Button 2, then Button 3 and lastly, Button 4. When I stop this python script by killing the python3 process in the task manager, I get the expected first behavior when restarting the script.

If I terminate the script in the console with Ctrl+C and restart this python script, I get the second behavior.

So maybe this has something to do with not correctly closing the python process? I'm really not sure what causes the program to behave in two different ways

5
  • 1
    This is essentially the same as your earlier question (but worse code). Try some of the earlier suggestions. – Milliways Mar 15 at 23:26
  • Instead of replying to all my questions by saying the code is bad (or worse), and giving vague answers ("The traditional approach is to set flags until the callback finishes.") to my questions, a short code example from your side on how to better write this would have actually helped me,since I'm new to callbacks and threading. – J.P. Mar 15 at 23:52
  • In my previous I advised "I would use separate callbacks for each button". (In fact I would gpiozero.) You were also advised by joan to avoid doing work in callbacks. In fact your code actually does nothing, so it is hard to suggest alternatives. This is still off-topic - it is a programming question and this is not a code writing service - particularly when previous attempts to help you find your own solution are ignored. – Milliways Mar 16 at 1:35
  • If you want some programming advice, perform your initialisation FIRST, drop the try (which appears to do nothing), get rid of the sleep which blocks code execution and use a separate callbacks for each button. It is easier to write good code than fix poorly structured code. – Milliways Mar 16 at 1:38
  • 1
1

I will just point out that the callback function is called from the event thread. The event thread will be blocked until the callback returns.

The second behaviour you see is the correct behaviour.

You only see the incorrect first behaviour because you are corrupting the Python system by killing one of its processes improperly.

2
  • So do I see it correctly that when main_function is called from within handleBtnPress, it is called in the same thread as the callback function and that's why the other button presses are queueing and executing one after the other? So you're saying I should never have time consuming operations started within a callback? Instead, setting a flag within the callback that a certain button has been pressed and then checking in the main program if there has been a flag set by this button press before starting a time consuming operation is the way to go? – J.P. Mar 15 at 22:44
  • @J.P. Yes, correct on all counts. – joan Mar 16 at 8:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.