Search code examples
pythonraspberry-pigpio

How to interrupt GPIO button triggered long running process with another event on Raspberry Pi?


I have 2 buttons wired to a Rapsberry Pi Zero W on the 38 and 40 pins. I have a long running process triggered to pin38 and I'd like to interrupt it once the pin40 is pushed. But pin 40 is inactive while the callback of pin38 is running. How can the long running proccess stopped via another event?

import RPi.GPIO as GPIO
import time

should_stop = False


def cb1(pin):
    if GPIO.input(pin) == 0:
        print("long running:", pin)

        global should_stop
        should_stop = False

        for _ in range(10):
            if not should_stop:
                print("long running is running")
                time.sleep(1)

        print("long running DONE")


def interrupt(pin):
    if GPIO.input(pin) == 0:
        print("fast running:", pin)

        global should_stop
        should_stop = True


GPIO.setmode(GPIO.BOARD)

GPIO.setup(38, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(40, GPIO.IN, pull_up_down=GPIO.PUD_UP)

GPIO.add_event_detect(38, GPIO.RISING, callback=cb1, bouncetime=300)
GPIO.add_event_detect(40, GPIO.RISING, callback=interrupt, bouncetime=300)

while True:
    time.sleep(1)

Solution

  • I've tested the following code on a PI and it works, it's using python a python process:

    import RPi.GPIO as GPIO
    
    import multiprocessing
    import time
    
    # function responsable for doing the heavy work when button1 is pressed
    # this function will stop doing the work when button 2 is pressed
    def long_processing(e):
        # runs for ever
        while True:
            # waits until the event is set
            e.wait()
            # do work while the event is set
            while e.is_set():
                # do some intensive work here
                print('intensive work...')
                time.sleep(0.5)
    
    
    if __name__ == '__main__':
        # initialize GPIO buttons
        GPIO.setmode(GPIO.BOARD)
        button1_pin = 16
        button2_pin = 12
        GPIO.setup(button1_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
        GPIO.setup(button2_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    
        first_button_pushed = multiprocessing.Event()
    
        # GPIO callbacks
        def but1_callback(channel):
            print('first button bushed')
            first_button_pushed.set()
    
        def but2_callback(channel):
            print('second button bushed')
            first_button_pushed.clear()
    
        # GPIO callbacks hooks
        GPIO.add_event_detect(button1_pin, GPIO.RISING, callback=but1_callback, bouncetime=300)
        GPIO.add_event_detect(button2_pin, GPIO.RISING, callback=but2_callback, bouncetime=300)
    
        # a process used to run the "long_processing" function in background
        # the first_button_pushed event is passed along
        process = multiprocessing.Process(name='first_process', target=long_processing, args=(first_button_pushed,))
        process.daemon = True
        process.start()
    
        while True:
            time.sleep(1)