diff --git a/README.md b/README.md index 6afda96..39d9798 100644 --- a/README.md +++ b/README.md @@ -55,13 +55,13 @@ $pin->setEdge(InputPinInterface::EDGE_BOTH); // Create an interrupt watcher $interruptWatcher = $gpio->createWatcher(); -// Register a callback to be triggered on pin interrupts +// Register a callback to be triggered on pin interrupts with a 500 millisecond debounce delay $interruptWatcher->register($pin, function (InputPinInterface $pin, $value) { echo 'Pin ' . $pin->getNumber() . ' changed to: ' . $value . PHP_EOL; // Returning false will make the watcher return false immediately return true; -}); +}, 500); // Watch for interrupts, timeout after 5000ms (5 seconds) while ($interruptWatcher->watch(5000)); diff --git a/src/Interrupt/InterruptWatcher.php b/src/Interrupt/InterruptWatcher.php index a85e98f..47d2578 100644 --- a/src/Interrupt/InterruptWatcher.php +++ b/src/Interrupt/InterruptWatcher.php @@ -12,6 +12,8 @@ class InterruptWatcher implements InterruptWatcherInterface private $streams; private $pins; private $callbacks; + private $delays; + private $lastCallbacks; /** * Constructor. @@ -40,7 +42,7 @@ public function __destruct() /** * {@inheritdoc} */ - public function register(InputPinInterface $pin, callable $callback) + public function register(InputPinInterface $pin, callable $callback, int $delay = 0) { $pinNumber = $pin->getNumber(); @@ -54,6 +56,8 @@ public function register(InputPinInterface $pin, callable $callback) $this->pins[$pinNumber] = $pin; $this->callbacks[$pinNumber] = $callback; + $this->debounceDelays[$pinNumber] = (float)$delay / 1000; + $this->lastCallbackMicrotimes[$pinNumber] = 0; } /** @@ -68,6 +72,7 @@ public function unregister(InputPinInterface $pin) unset($this->streams[$pinNumber]); unset($this->callbacks[$pinNumber]); + unset($this->debounceDelays[$pinNumber]); unset($this->pins[$pinNumber]); } } @@ -81,6 +86,8 @@ public function watch($timeout) $carry = $timeout - ($seconds * 1000); $micro = $carry * 1000; + $microtimeNow = microtime(true); + $read = $write = []; $except = $this->streams; @@ -103,6 +110,16 @@ public function watch($timeout) } foreach ($triggers as $pinNumber => $value) { + if ($this->debounceDelays[$pinNumber] !== 0 + && $this->lastCallbackMicrotimes[$pinNumber] !== 0 + && ($microtimeNow - $this->lastCallbackMicrotimes[$pinNumber] < $this->debounceDelays[$pinNumber]) + ) { + + return true; + } + + $this->lastCallbackMicrotimes[$pinNumber] = $microtimeNow; + if (false === call_user_func($this->callbacks[$pinNumber], $this->pins[$pinNumber], $value)) { return false; } diff --git a/src/Interrupt/InterruptWatcherInterface.php b/src/Interrupt/InterruptWatcherInterface.php index c802934..a309b00 100644 --- a/src/Interrupt/InterruptWatcherInterface.php +++ b/src/Interrupt/InterruptWatcherInterface.php @@ -11,8 +11,9 @@ interface InterruptWatcherInterface * * @param InputPinInterface $pin * @param callable $callback + * @param integer $delay time in ms between callbacks */ - public function register(InputPinInterface $pin, callable $callback); + public function register(InputPinInterface $pin, callable $callback, int $delay = 0); /** * Unregister a pin callback.