package com.pi4j.io.gpio.impl;
/*
* #%L
* **********************************************************************
* ORGANIZATION : Pi4J
* PROJECT : Pi4J :: Java Library (Core)
* FILENAME : GpioPinImpl.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.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import com.pi4j.io.gpio.GpioPinAnalogInput;
import com.pi4j.io.gpio.GpioPinAnalogOutput;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioPinDigitalInput;
import com.pi4j.io.gpio.GpioPinDigitalMultipurpose;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.GpioPin;
import com.pi4j.io.gpio.GpioPinInput;
import com.pi4j.io.gpio.GpioPinOutput;
import com.pi4j.io.gpio.GpioPinPwmOutput;
import com.pi4j.io.gpio.GpioProvider;
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.PinMode;
import com.pi4j.io.gpio.PinPullResistance;
import com.pi4j.io.gpio.GpioPinShutdown;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.event.GpioPinListener;
import com.pi4j.io.gpio.event.PinListener;
import com.pi4j.io.gpio.trigger.GpioTrigger;
public class GpioPinImpl implements GpioPin,
GpioPinDigitalInput,
GpioPinDigitalOutput,
GpioPinDigitalMultipurpose,
GpioPinAnalogInput,
GpioPinAnalogOutput,
GpioPinPwmOutput,
GpioPinInput,
GpioPinOutput
{
@SuppressWarnings("unused")
private final GpioController gpio;
private String name = null;
private Object tag = null;
private final GpioProvider provider;
private final Pin pin;
private PinListener monitor;
private final GpioPinShutdownImpl shutdownOptions;
private final Map<String, String> properties = new ConcurrentHashMap<String, String>();
private final List<GpioPinListener> listeners = new ArrayList<GpioPinListener>();
private final List<GpioTrigger> triggers = new ArrayList<GpioTrigger>();
public GpioPinImpl(GpioController gpio, GpioProvider provider, Pin pin) {
this.gpio = gpio;
this.provider = provider;
this.pin = pin;
shutdownOptions = new GpioPinShutdownImpl();
}
@Override
public Pin getPin() {
return this.pin;
}
@Override
public GpioProvider getProvider() {
return this.provider;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getName() {
if (name == null || name.length() == 0) {
return pin.toString();
}
return name;
}
@Override
public void setTag(Object tag) {
this.tag = tag;
}
@Override
public Object getTag() {
return tag;
}
@Override
public void setProperty(String key, String value) {
properties.put(key, value);
}
@Override
public boolean hasProperty(String key) {
return properties.containsKey(key);
}
@Override
public String getProperty(String key, String defaultValue) {
if (properties.containsKey(key)) {
if(properties.get(key) == null || properties.get(key).isEmpty())
return defaultValue;
else
return properties.get(key);
}
return defaultValue;
}
@Override
public String getProperty(String key) {
return getProperty(key, null);
}
@Override
public Map<String, String> getProperties() {
return properties;
}
@Override
public void removeProperty(String key) {
if (properties.containsKey(key)) {
properties.remove(key);
}
}
@Override
public void clearProperties() {
properties.clear();
}
@Override
public void export(PinMode mode) {
// export the pin
provider.export(pin, mode);
}
@Override
public void unexport() {
// unexport the pin
provider.unexport(pin);
}
@Override
public boolean isExported() {
return provider.isExported(pin);
}
@Override
public void setMode(PinMode mode) {
provider.setMode(pin, mode);
}
@Override
public PinMode getMode() {
return provider.getMode(pin);
}
@Override
public boolean isMode(PinMode mode) {
return (getMode() == mode);
}
@Override
public void setPullResistance(PinPullResistance resistance) {
provider.setPullResistance(pin, resistance);
}
@Override
public PinPullResistance getPullResistance() {
return provider.getPullResistance(pin);
}
@Override
public boolean isPullResistance(PinPullResistance resistance) {
return (getPullResistance() == resistance);
}
@Override
public void high() {
setState(PinState.HIGH);
}
@Override
public void low() {
setState(PinState.LOW);
}
@Override
public void toggle() {
if (getState() == PinState.HIGH) {
setState(PinState.LOW);
} else {
setState(PinState.HIGH);
}
}
@Override
public Future<?> blink(long delay) {
return blink(delay, PinState.HIGH);
}
@Override
public Future<?> blink(long delay, PinState blinkState) {
// NOTE: a value of 0 milliseconds will stop the blinking
return blink(delay, 0, blinkState);
}
@Override
public Future<?> blink(long delay, long duration) {
return blink(delay, duration, PinState.HIGH);
}
@Override
public Future<?> blink(long delay, long duration, PinState blinkState) {
// NOTE: a value of 0 milliseconds will stop the blinking
return GpioScheduledExecutorImpl.blink(this, delay, duration, blinkState);
}
@Override
public Future<?> pulse(long duration) {
return pulse(duration, false);
}
@Override
public Future<?> pulse(long duration, PinState pulseState) {
return pulse(duration, pulseState, false);
}
@Override
public Future<?> pulse(long duration, boolean blocking) {
return pulse(duration, PinState.HIGH, blocking);
}
@Override
public Future<?> pulse(long duration, PinState pulseState, boolean blocking) {
// validate duration argument
if(duration <= 0)
throw new IllegalArgumentException("Pulse duration must be greater than 0 milliseconds.");
// if this is a blocking pulse, then execute the pulse
// and sleep the caller's thread to block the operation
// until the pulse is complete
if(blocking) {
// start the pulse state
setState(pulseState);
// block the current thread for the pulse duration
try {
Thread.sleep(duration);
}
catch (InterruptedException e) {
throw new RuntimeException("Pulse blocking thread interrupted.", e);
}
// end the pulse state
setState(PinState.getInverseState(pulseState));
// we are done; no future is returned for blocking pulses
return null;
}
else {
// if this is not a blocking call, then setup the pulse
// instruction to be completed in a background worker
// thread pool using a scheduled executor
return GpioScheduledExecutorImpl.pulse(this, duration, pulseState);
}
}
@Override
public void setState(PinState state) {
provider.setState(pin, state);
}
@Override
public void setState(boolean state) {
provider.setState(pin, (state) ? PinState.HIGH : PinState.LOW);
}
@Override
public boolean isHigh() {
return (getState() == PinState.HIGH);
}
@Override
public boolean isLow() {
return (getState() == PinState.LOW);
}
@Override
public PinState getState() {
return provider.getState(pin);
}
@Override
public boolean isState(PinState state) {
return (getState() == state);
}
@Override
public void setValue(double value) {
provider.setValue(pin, value);
}
@Override
public double getValue() {
return provider.getValue(pin);
}
@Override
public void setPwm(int value) {
provider.setPwm(pin, value);
}
@Override
public int getPwm() {
return provider.getPwm(pin);
}
private synchronized void updateInterruptListener() {
if (listeners.size() > 0 || triggers.size() > 0) {
if (monitor == null) {
// create new monitor and register for event callbacks
monitor = new GpioEventMonitorExecutorImpl(this);
provider.addListener(pin, monitor);
}
} else {
if (monitor != null) {
// remove monitor and unregister for event callbacks
provider.removeListener(pin, monitor);
// destroy monitor instance
monitor = null;
}
}
}
/**
*
* @param listener
*/
public synchronized void addListener(GpioPinListener... listener) {
if (listener == null || listener.length == 0) {
throw new IllegalArgumentException("Missing listener argument.");
}
for (GpioPinListener lsnr : listener) {
listeners.add(lsnr);
}
updateInterruptListener();
}
public synchronized void addListener(List<? extends GpioPinListener> listeners) {
for (GpioPinListener listener : listeners) {
addListener(listener);
}
}
/**
*
* @param listener
*/
public synchronized Collection<GpioPinListener> getListeners() {
return listeners;
}
@Override
public boolean hasListener(GpioPinListener... listener) {
if (listener == null || listener.length == 0) {
throw new IllegalArgumentException("Missing listener argument.");
}
for (GpioPinListener lsnr : listener) {
if (!listeners.contains(lsnr)) {
return false;
}
}
return true;
}
public synchronized void removeListener(GpioPinListener... listener) {
if (listener == null || listener.length == 0) {
throw new IllegalArgumentException("Missing listener argument.");
}
for (GpioPinListener lsnr : listener) {
listeners.remove(lsnr);
}
updateInterruptListener();
}
public synchronized void removeListener(List<? extends GpioPinListener> listeners) {
for (GpioPinListener listener : listeners) {
removeListener(listener);
}
}
public synchronized void removeAllListeners() {
for (int index = (listeners.size()-1); index >= 0; index --) {
GpioPinListener listener = listeners.get(index);
removeListener(listener);
}
}
/**
*
* @param trigger
*/
public synchronized Collection<GpioTrigger> getTriggers() {
return triggers;
}
public synchronized void addTrigger(GpioTrigger... trigger) {
if (trigger == null || trigger.length == 0) {
throw new IllegalArgumentException("Missing trigger argument.");
}
for (GpioTrigger trgr : trigger) {
triggers.add(trgr);
}
updateInterruptListener();
}
public synchronized void addTrigger(List<? extends GpioTrigger> triggers) {
for (GpioTrigger trigger : triggers) {
addTrigger(trigger);
}
}
/**
*
* @param trigger
*/
public synchronized void removeTrigger(GpioTrigger... trigger) {
if (trigger == null || trigger.length == 0) {
throw new IllegalArgumentException("Missing trigger argument.");
}
for (GpioTrigger trgr : trigger) {
triggers.remove(trgr);
}
updateInterruptListener();
}
public synchronized void removeTrigger(List<? extends GpioTrigger> triggers) {
for (GpioTrigger trigger : triggers) {
removeTrigger(trigger);
}
}
public synchronized void removeAllTriggers() {
for (int index = triggers.size() - 1; index >= 0; index--) {
GpioTrigger trigger = triggers.get(index);
removeTrigger(trigger);
}
}
@Override
public String toString() {
if (name != null && !name.isEmpty()) {
return String.format("\"%s\" <%s>", name, pin.toString());
} else {
return pin.toString();
}
}
@Override
public GpioPinShutdown getShutdownOptions() {
return shutdownOptions;
}
@Override
public void setShutdownOptions(GpioPinShutdown options) {
shutdownOptions.setUnexport(options.getUnexport());
shutdownOptions.setState(options.getState());
shutdownOptions.setMode(options.getMode());
shutdownOptions.setPullResistor(options.getPullResistor());
}
@Override
public void setShutdownOptions(Boolean unexport) {
setShutdownOptions(unexport, null);
}
@Override
public void setShutdownOptions(Boolean unexport, PinState state) {
setShutdownOptions(unexport, state, null);
}
@Override
public void setShutdownOptions(Boolean unexport, PinState state, PinPullResistance resistance)
{
setShutdownOptions(unexport, state, resistance, null);
}
@Override
public void setShutdownOptions(Boolean unexport, PinState state, PinPullResistance resistance, PinMode mode) {
shutdownOptions.setUnexport(unexport);
shutdownOptions.setState(state);
shutdownOptions.setMode(mode);
shutdownOptions.setPullResistor(resistance);
}
}