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 - 2013 Pi4J * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; 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; /** * Abstract base implementation of {@link GpioProvider}. * * @author Robert Savage (<a * href="http://www.savagehomeautomation.com">http://www.savagehomeautomation.com</a>) */ public abstract class GpioProviderBase implements GpioProvider { public abstract String getName(); protected final Map<Pin, List<PinListener>> listeners = new ConcurrentHashMap<Pin, List<PinListener>>(); protected final Map<Pin, GpioProviderPinCache> cache = new ConcurrentHashMap<Pin, GpioProviderPinCache>(); protected boolean isshutdown = false; @Override public boolean hasPin(Pin pin) { return (pin.getProvider() == 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) { if (hasPin(pin) == false) { 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) == false) { throw new InvalidPinException(pin); } // return cached exported state return getPinCache(pin).isExported(); } @Override public void unexport(Pin pin) { if (hasPin(pin) == false) { 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) == false) { throw new InvalidPinException(pin); } // return cached mode value return getPinCache(pin).getMode(); } @Override public void setPullResistance(Pin pin, PinPullResistance resistance) { if (hasPin(pin) == false) { 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) == false) { throw new InvalidPinException(pin); } // return cached resistance return getPinCache(pin).getResistance(); } @Override public void setState(Pin pin, PinState state) { if (hasPin(pin) == false) { 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() + "]"); } // cache pin state getPinCache(pin).setState(state); } @Override public PinState getState(Pin pin) { if (hasPin(pin) == false) { 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) == false) { 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() + "]"); } // cache pin analog value getPinCache(pin).setAnalogValue(value); } @Override public double getValue(Pin pin) { if (hasPin(pin) == false) { 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) == false) { 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) == false) { throw new InvalidPinException(pin); } // return cached pin PWM value return getPinCache(pin).getPwmValue(); } @Override public void addListener(Pin pin, PinListener listener) { // create new pin listener entry if one does not already exist if (!listeners.containsKey(pin)) { listeners.put(pin, new ArrayList<PinListener>()); } // add the listener instance to the listeners map entry List<PinListener> lsnrs = listeners.get(pin); if (!lsnrs.contains(listener)) { lsnrs.add(listener); } } @Override public void removeListener(Pin pin, PinListener listener) { // lookup to pin entry in the listeners map if (listeners.containsKey(pin)) { // remote the listener instance from the listeners map entry if found List<PinListener> 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() { // iterate over all listener pins in the map for (Pin pin : listeners.keySet()) { // iterate over all listener handler in the map entry // and remove each listener handler instance for (PinListener listener : listeners.get(pin)) { 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; // 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; } }