From 8b332c04c1a90522103947d8e7a1c96fb539c98d Mon Sep 17 00:00:00 2001 From: Alexander Wellbrock <a.wellbrock@mailbox.org> Date: Mon, 11 Jan 2021 12:20:49 +0100 Subject: [PATCH] rewrite interrupt handler as thread class This approach moves the interrupt wait logic into it's own thread. This does not yet work as the previous solution did not too. The previous solution didn't actually register the interrupt. The new one does try to register the interrupt but fails, since the line is already bound as an input type from the pin init method before the interrupt is called. Tried approaches to free the pin before trying to bind it again or to find out if the input should be an interrupt did not work yet. --- pi_mqtt_gpio/modules/gpiod.py | 52 +++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/pi_mqtt_gpio/modules/gpiod.py b/pi_mqtt_gpio/modules/gpiod.py index 3c32a82..bab01dd 100644 --- a/pi_mqtt_gpio/modules/gpiod.py +++ b/pi_mqtt_gpio/modules/gpiod.py @@ -1,7 +1,9 @@ from pi_mqtt_gpio.modules import GenericGPIO, PinDirection, PinPullup, \ InterruptEdge -from threading import Thread +import threading +import queue +from datetime import datetime, timedelta # Requires libgpiod-devel, libgpiod REQUIREMENTS = ("gpiod",) @@ -19,7 +21,6 @@ PULLUPS = None INTERRUPT = None GPIO_INTERRUPT_CALLBACK_LOOKUP = {} - class GPIO(GenericGPIO): """ Implementation of GPIO class for libgpiod (linux kernel >= 4.8). @@ -74,20 +75,17 @@ class GPIO(GenericGPIO): callback: the callback function to be called, when interrupt occurs bouncetime: minimum time between two interrupts """ - edge = INTERRUPT[edge] - offset = pin - - pin = self.chip.get_line(offset) config = self.io.line_request() config.consumer = 'pi-mqtt-gpio' - config.request_type = edge + config.request_type = INTERRUPT[edge] - t = Thread(target=self._event_detect, args=(pin,self.interrupt_callback,)) + t = GpioThread(chip=self.chip, offset=pin, config=config, + callback=callback, bouncetime=bouncetime) t.start() self.watchers[offset] = t - self.GPIO_INTERRUPT_CALLBACK_LOOKUP[offset] = {"handle": handle, + self.GPIO_INTERRUPT_CALLBACK_LOOKUP[offset] = {"handle": t.handle, "callback": callback} def set_pin(self, pin, value): @@ -101,7 +99,37 @@ class GPIO(GenericGPIO): def cleanup(self): pass - def _event_detect(self, pin, callback): +class GpioThread(threading.Thread): + def __init__(self, chip, offset, config, callback, bouncetime): + super().__init__() + self.daemon = True + self._queue = queue.Queue() + + self.pin = chip.get_line(offset) + self.pin.request(config) + self.callback = callback + self.bouncetime = timedelta(microseconds=bouncetime) + + def run(self): + previous_event_time = datetime.now() while True: - if pin.event_wait(): - callback() + if self.pin.event_wait(): + event = self.pin.event_read() + if event.timestamp - previous_event_time > self.bouncetime: + previous_event_time = event.timestamp + + ret = self.callback() + self._queue.put( + { + "type": event.event_type, + "time": event.timestamp, + "result": ret, + } + ) + + @property + def handle(self): + if self._queue.empty(): + return None + + return self._queue.get() \ No newline at end of file -- GitLab