001package com.pi4j.io.gpio.impl;
002
003/*
004 * #%L
005 * **********************************************************************
006 * ORGANIZATION  :  Pi4J
007 * PROJECT       :  Pi4J :: Java Library (Core)
008 * FILENAME      :  GpioEventMonitorExecutorImpl.java
009 *
010 * This file is part of the Pi4J project. More information about
011 * this project can be found here:  https://www.pi4j.com/
012 * **********************************************************************
013 * %%
014 * Copyright (C) 2012 - 2021 Pi4J
015 * %%
016 * This program is free software: you can redistribute it and/or modify
017 * it under the terms of the GNU Lesser General Public License as
018 * published by the Free Software Foundation, either version 3 of the
019 * License, or (at your option) any later version.
020 *
021 * This program is distributed in the hope that it will be useful,
022 * but WITHOUT ANY WARRANTY; without even the implied warranty of
023 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
024 * GNU General Lesser Public License for more details.
025 *
026 * You should have received a copy of the GNU General Lesser Public
027 * License along with this program.  If not, see
028 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
029 * #L%
030 */
031
032import com.pi4j.io.gpio.GpioFactory;
033import com.pi4j.io.gpio.GpioPinDigitalInput;
034import com.pi4j.io.gpio.GpioPinInput;
035import com.pi4j.io.gpio.PinState;
036import com.pi4j.io.gpio.event.PinDigitalStateChangeEvent;
037import com.pi4j.io.gpio.event.PinEvent;
038import com.pi4j.io.gpio.event.PinEventType;
039import com.pi4j.io.gpio.event.PinListener;
040import com.pi4j.io.gpio.tasks.impl.GpioEventDebounceTaskImpl;
041import com.pi4j.io.gpio.tasks.impl.GpioEventDispatchTaskImpl;
042
043import java.util.concurrent.ExecutorService;
044import java.util.concurrent.ScheduledExecutorService;
045import java.util.concurrent.ScheduledFuture;
046import java.util.concurrent.TimeUnit;
047
048public class GpioEventMonitorExecutorImpl implements PinListener {
049
050    private final GpioPinInput pin;
051    private static ExecutorService executor;
052    private static ScheduledExecutorService scheduledExecutor;
053    private ScheduledFuture<?> debounceFuture = null;
054
055    public GpioEventMonitorExecutorImpl(GpioPinInput pin) {
056        this.pin = pin;
057        executor = GpioFactory.getExecutorServiceFactory().getGpioEventExecutorService();
058        scheduledExecutor = GpioFactory.getExecutorServiceFactory().getScheduledExecutorService();
059    }
060
061    @Override
062    public void handlePinEvent(PinEvent event) {
063
064        // for digital input pins, we need to enforce pin debounce event suppression
065        if(pin instanceof GpioPinDigitalInput && event.getEventType() == PinEventType.DIGITAL_STATE_CHANGE){
066
067            // cast to the digital input pin interface, get the current state from
068            // the event, and determine the debounce interval for this pin state
069            GpioPinDigitalInput dip = (GpioPinDigitalInput)pin;
070            PinState state = ((PinDigitalStateChangeEvent) event).getState();
071            int pinDebounceForState = dip.getDebounce(state);
072
073            // if the pin has a debounce delay configured for this pin state,
074            // then we will need to use the pin debounce logic to defer pin events
075            if(pinDebounceForState > 0) {
076                // if no existing debounce future task exists or no future task is still busy, then
077                // create a new debounce future task and schedule it based on the debounce
078                // interval defined for the current pin state
079                if (debounceFuture == null || debounceFuture.isDone()) {
080                    debounceFuture = scheduledExecutor.schedule(
081                            new GpioEventDebounceTaskImpl(dip, state), pinDebounceForState, TimeUnit.MILLISECONDS);
082                } else {
083                    // if an existing debounce future task exists and is still busy,
084                    // then exit this method effectively suppressing the current pin event
085                    return;
086                }
087            }
088        }
089
090        // add a new pin event notification to the thread pool for *immediate* execution
091        executor.execute(new GpioEventDispatchTaskImpl(pin, event));
092    }
093}