All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.pi4j.io.gpio.GpioProviderBase Maven / Gradle / Ivy

There is a newer version: 3.0.1
Show newest version
package com.pi4j.io.gpio;

/*
 * #%L
 * **********************************************************************
 * ORGANIZATION  :  Pi4J
 * PROJECT       :  Pi4J :: Java Library (Core)
 * FILENAME      :  GpioProviderBase.java  
 * 
 * This file is part of the Pi4J project. More information about 
 * this project can be found here:  http://www.pi4j.com/
 * **********************************************************************
 * %%
 * Copyright (C) 2012 - 2015 Pi4J
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */


import com.pi4j.io.gpio.event.PinAnalogValueChangeEvent;
import com.pi4j.io.gpio.event.PinDigitalStateChangeEvent;
import com.pi4j.io.gpio.event.PinListener;
import com.pi4j.io.gpio.exception.InvalidPinException;
import com.pi4j.io.gpio.exception.InvalidPinModeException;
import com.pi4j.io.gpio.exception.UnsupportedPinModeException;
import com.pi4j.io.gpio.exception.UnsupportedPinPullResistanceException;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Abstract base implementation of {@link com.pi4j.io.gpio.GpioProvider}.
 *
 * @author Robert Savage (http://www.savagehomeautomation.com)
 */
@SuppressWarnings("unused")
public abstract class GpioProviderBase implements GpioProvider {

    public abstract String getName();

    protected final Map> listeners = new ConcurrentHashMap<>();
    protected final Map cache = new ConcurrentHashMap<>();
    protected boolean isshutdown = false;
    
    @Override
    public boolean hasPin(Pin pin) {
        return (pin.getProvider().equals(getName()));
    }
    
    protected GpioProviderPinCache getPinCache(Pin pin) {
        if (!cache.containsKey(pin)) {
            cache.put(pin, new GpioProviderPinCache(pin));
        }
        return cache.get(pin);
    }

    @Override
    public void export(Pin pin, PinMode mode, PinState defaultState) {
        // export the pin and set it's mode
        export(pin, mode);

        // apply default state if one was provided and only if this pin is a digital output
        if(defaultState != null && mode == PinMode.DIGITAL_OUTPUT) {
            setState(pin, defaultState);
        }
    }

    @Override
    public void export(Pin pin, PinMode mode) {
        if (!hasPin(pin)) {
            throw new InvalidPinException(pin);
        }

        if (!pin.getSupportedPinModes().contains(mode)) {
            throw new UnsupportedPinModeException(pin, mode);
        }

        // cache exported state
        getPinCache(pin).setExported(true);

        // cache mode
        getPinCache(pin).setMode(mode);
    }
    
    @Override
    public boolean isExported(Pin pin) {
        if (!hasPin(pin)) {
            throw new InvalidPinException(pin);
        }
        
        // return cached exported state
        return getPinCache(pin).isExported();
    }

    @Override
    public void unexport(Pin pin) {
        if (!hasPin(pin)) {
            throw new InvalidPinException(pin);
        }
        
        // cache exported state
        getPinCache(pin).setExported(false);
    }

    @Override
    public void setMode(Pin pin, PinMode mode) {
        if (!pin.getSupportedPinModes().contains(mode)) {
            throw new InvalidPinModeException(pin, "Invalid pin mode [" + mode.getName() + "]; pin [" + pin.getName() + "] does not support this mode.");
        }

        if (!pin.getSupportedPinModes().contains(mode)) {
            throw new UnsupportedPinModeException(pin, mode);
        }
        
        // cache mode
        getPinCache(pin).setMode(mode);
    }

    @Override
    public PinMode getMode(Pin pin) {
        if (!hasPin(pin)) {
            throw new InvalidPinException(pin);
        }

        // return cached mode value
        return getPinCache(pin).getMode();
    }
    
    
    @Override
    public void setPullResistance(Pin pin, PinPullResistance resistance) {
        if (!hasPin(pin)) {
            throw new InvalidPinException(pin);
        }
        
        if (!pin.getSupportedPinPullResistance().contains(resistance)) {
            throw new UnsupportedPinPullResistanceException(pin, resistance);
        }
        
        // cache resistance
        getPinCache(pin).setResistance(resistance);
    }

    @Override
    public PinPullResistance getPullResistance(Pin pin) {
        if (!hasPin(pin)) {
            throw new InvalidPinException(pin);
        }
        
        // return cached resistance
        return getPinCache(pin).getResistance();
    }
    
    @Override
    public void setState(Pin pin, PinState state) {
        if (!hasPin(pin)) {
            throw new InvalidPinException(pin);
        }

        PinMode mode = getMode(pin);
        
        // only permit invocation on pins set to DIGITAL_OUTPUT modes 
        if (mode != PinMode.DIGITAL_OUTPUT) {
            throw new InvalidPinModeException(pin, "Invalid pin mode on pin [" + pin.getName() + "]; cannot setState() when pin mode is [" + mode.getName() + "]");
        }

        // for digital output pins, we will echo the event feedback
        dispatchPinDigitalStateChangeEvent(pin, state);

        // cache pin state
        getPinCache(pin).setState(state);
    }

    @Override
    public PinState getState(Pin pin) {
        if (!hasPin(pin)) {
            throw new InvalidPinException(pin);
        }
        
        PinMode mode = getMode(pin);

        // only permit invocation on pins set to DIGITAL modes 
        if (!PinMode.allDigital().contains(mode)) {
            throw new InvalidPinModeException(pin, "Invalid pin mode on pin [" + pin.getName() + "]; cannot getState() when pin mode is [" + mode.getName() + "]");
        }

        // return cached pin state
        return getPinCache(pin).getState();           
    }

    @Override
    public void setValue(Pin pin, double value) {
        if (!hasPin(pin)) {
            throw new InvalidPinException(pin);
        }
        
        PinMode mode = getMode(pin);

        // only permit invocation on pins set to OUTPUT modes 
        if (!PinMode.allOutput().contains(mode)) {
            throw new InvalidPinModeException(pin, "Invalid pin mode on pin [" + pin.getName() + "]; cannot setValue(" + value + ") when pin mode is [" + mode.getName() + "]");
        }

        // for digital analog pins, we will echo the event feedback
        dispatchPinAnalogValueChangeEvent(pin, value);

        // cache pin analog value
        getPinCache(pin).setAnalogValue(value);                        
    }

    @Override
    public double getValue(Pin pin) {
        if (!hasPin(pin)) {
            throw new InvalidPinException(pin);
        }

        PinMode mode = getMode(pin);
        
        if (mode == PinMode.DIGITAL_OUTPUT) {
            return getState(pin).getValue(); 
        }
        
        // return cached pin analog value
        return getPinCache(pin).getAnalogValue();                             
    }
    
    @Override
    public void setPwm(Pin pin, int value) {
        if (!hasPin(pin)) {
            throw new InvalidPinException(pin);        
        }
        
        PinMode mode = getMode(pin);

        if (mode != PinMode.PWM_OUTPUT) {
            throw new InvalidPinModeException(pin, "Invalid pin mode [" + mode.getName() + "]; unable to setPwm(" + value + ")");
        }
        
        // cache pin PWM value
        getPinCache(pin).setPwmValue(value);                       
    }
    
    
    @Override
    public int getPwm(Pin pin) {
        if (!hasPin(pin)) {
            throw new InvalidPinException(pin);
        }

        // return cached pin PWM value
        return getPinCache(pin).getPwmValue();                           
    }

    @Override
    public void addListener(Pin pin, PinListener listener) {
        synchronized (listeners) {
            // create new pin listener entry if one does not already exist
            if (!listeners.containsKey(pin)) {
                listeners.put(pin, new ArrayList());
            }

            // add the listener instance to the listeners map entry
            List lsnrs = listeners.get(pin);
            if (!lsnrs.contains(listener)) {
                lsnrs.add(listener);
            }
        }
    }
    
    @Override
    public void removeListener(Pin pin, PinListener listener) {
        synchronized (listeners) {
            // lookup to pin entry in the listeners map
            if (listeners.containsKey(pin)) {
                // remote the listener instance from the listeners map entry if found
                List lsnrs = listeners.get(pin);
                if (lsnrs.contains(listener)) {
                    lsnrs.remove(listener);
                }

                // if the listener list is empty, then remove the listener pin from the map
                if (lsnrs.isEmpty()) {
                    listeners.remove(pin);
                }
            }
        }
    }    
    
    @Override
    public void removeAllListeners() {
        synchronized (listeners) {
            // iterate over all listener pins in the map
            List pins_copy = new ArrayList<>(listeners.keySet());
            for (Pin pin : pins_copy) {
                if(listeners.containsKey(pin)) {
                    // iterate over all listener handler in the map entry
                    // and remove each listener handler instance
                    List lsnrs = listeners.get(pin);
                    if (!lsnrs.isEmpty()) {
                        List lsnrs_copy = new ArrayList<>(lsnrs);
                        for (int index = lsnrs_copy.size() - 1; index >= 0; index--) {
                            PinListener listener = lsnrs_copy.get(index);
                            removeListener(pin, listener);
                        }
                    }
                }
            }
        }
    }
    
    protected void dispatchPinDigitalStateChangeEvent(Pin pin, PinState state) {
        // if the pin listeners map contains this pin, then dispatch event
        if (listeners.containsKey(pin)) {
            // dispatch this event to all listener handlers
            for (PinListener listener : listeners.get(pin)) {
                listener.handlePinEvent(new PinDigitalStateChangeEvent(this, pin, state));
            }            
        }
    }
    
    protected void dispatchPinAnalogValueChangeEvent(Pin pin, double value) {
        // if the pin listeners map contains this pin, then dispatch event
        if (listeners.containsKey(pin)) {
            // dispatch this event to all listener handlers
            for (PinListener listener : listeners.get(pin)) {
                listener.handlePinEvent(new PinAnalogValueChangeEvent(this, pin, value));
            }            
        }
    }
    
    @Override
    public void shutdown() {
        
        // prevent reentrant invocation
        if(isShutdown())
            return;

        // remove all listeners
        removeAllListeners();
        
        // set shutdown tracking state variable
        isshutdown = true;
    }     
        
    /**
     * This method returns TRUE if the GPIO provider has been shutdown.
     * 
     * @return shutdown state
     */
    @Override
    public boolean isShutdown(){
        return isshutdown;
    }    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy