001package com.pi4j.io.gpio;
002
003import com.pi4j.io.gpio.event.PinListener;
004import com.pi4j.wiringpi.GpioInterruptEvent;
005import com.pi4j.wiringpi.GpioInterruptListener;
006
007/*
008 * #%L
009 * **********************************************************************
010 * ORGANIZATION  :  Pi4J
011 * PROJECT       :  Pi4J :: Java Library (Core)
012 * FILENAME      :  RaspiGpioProvider.java  
013 * 
014 * This file is part of the Pi4J project. More information about 
015 * this project can be found here:  http://www.pi4j.com/
016 * **********************************************************************
017 * %%
018 * Copyright (C) 2012 - 2013 Pi4J
019 * %%
020 * Licensed under the Apache License, Version 2.0 (the "License");
021 * you may not use this file except in compliance with the License.
022 * You may obtain a copy of the License at
023 * 
024 *      http://www.apache.org/licenses/LICENSE-2.0
025 * 
026 * Unless required by applicable law or agreed to in writing, software
027 * distributed under the License is distributed on an "AS IS" BASIS,
028 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
029 * See the License for the specific language governing permissions and
030 * limitations under the License.
031 * #L%
032 */
033
034/**
035 * Raspberry PI {@link GpioProvider} implementation.
036 *
037 * @author Robert Savage (<a
038 *         href="http://www.savagehomeautomation.com">http://www.savagehomeautomation.com</a>)
039 */
040public class RaspiGpioProvider extends GpioProviderBase implements GpioProvider, GpioInterruptListener {
041    
042    public static final String NAME = "RaspberryPi GPIO Provider";
043    
044    public RaspiGpioProvider() {
045        // set wiringPi interface for internal use
046        // we will use the WiringPi pin number scheme with the wiringPi library
047        com.pi4j.wiringpi.Gpio.wiringPiSetup();
048    }
049    
050    @Override
051    public String getName() {
052        return NAME;
053    }
054
055    @Override
056    public boolean hasPin(Pin pin) {
057        return (com.pi4j.wiringpi.Gpio.wpiPinToGpio(pin.getAddress()) >= 0);
058    }
059
060    @Override
061    public void export(Pin pin, PinMode mode) {
062        super.export(pin, mode);
063       
064        //System.out.println("-- EXPORTING PIN [" + pin.getAddress() + "] to mode [" + mode.getName() + "]");       
065        
066        // export the pin and set the mode
067        com.pi4j.wiringpi.GpioUtil.export(pin.getAddress(), mode.getDirection().getValue());
068        setMode(pin, mode);
069    }
070
071    @Override
072    public boolean isExported(Pin pin) {
073        super.isExported(pin);
074        
075        // return the pin exported state
076        return com.pi4j.wiringpi.GpioUtil.isExported(pin.getAddress());
077    }
078
079    @Override
080    public void unexport(Pin pin) {
081        super.unexport(pin);
082
083        // unexport the pins
084        com.pi4j.wiringpi.GpioUtil.unexport(pin.getAddress());
085    }
086
087    @Override
088    public void setMode(Pin pin, PinMode mode) {
089        super.setMode(pin, mode);
090
091        com.pi4j.wiringpi.Gpio.pinMode(pin.getAddress(), mode.getValue());
092        
093        // if this is an input pin, then configure edge detection
094        if (PinMode.allInputs().contains(mode)) {
095            com.pi4j.wiringpi.GpioUtil.setEdgeDetection(pin.getAddress(), PinEdge.BOTH.getValue());
096        }
097    }
098
099    @Override
100    public PinMode getMode(Pin pin) {
101        // TODO : get actual pin mode from native impl
102        return super.getMode(pin);
103    }
104    
105    @Override
106    public void setPullResistance(Pin pin, PinPullResistance resistance) {
107        super.setPullResistance(pin, resistance);
108
109        com.pi4j.wiringpi.Gpio.pullUpDnControl(pin.getAddress(), resistance.getValue());
110    }
111
112    @Override
113    public PinPullResistance getPullResistance(Pin pin) {
114        // TODO : get actual pin pull resistance from native impl
115        return super.getPullResistance(pin);
116    }
117    
118    @Override
119    public void setState(Pin pin, PinState state) {
120        super.setState(pin, state);
121
122        com.pi4j.wiringpi.Gpio.digitalWrite(pin.getAddress(), state.getValue());        
123    }
124
125    @Override
126    public PinState getState(Pin pin) {
127        super.getState(pin);
128        
129        // return pin state
130        PinState state = null;
131        int ret = com.pi4j.wiringpi.Gpio.digitalRead(pin.getAddress());
132        if (ret >= 0) {
133            state = PinState.getState(ret);
134        }
135        return state;
136    }
137
138    @Override
139    public void setValue(Pin pin, double value) {
140        super.setValue(pin, value);
141        throw new RuntimeException("This GPIO provider does not support analog pins.");
142    }
143
144    @Override
145    public double getValue(Pin pin) {
146        super.getValue(pin);
147        throw new RuntimeException("This GPIO provider does not support analog pins.");
148    }
149
150    @Override
151    public void setPwm(Pin pin, int value) {
152        super.setPwm(pin, value);
153
154        if (getMode(pin) == PinMode.PWM_OUTPUT) {
155            setPwmValue(pin, value);
156        }
157    }
158
159    @Override
160    public int getPwm(Pin pin) {
161        return super.getPwm(pin);
162    }
163    
164    // internal
165    private void setPwmValue(Pin pin, int value) {
166        // set pin PWM value
167        com.pi4j.wiringpi.Gpio.pwmWrite(pin.getAddress(), value);
168    }
169
170    @Override
171    public void pinStateChange(GpioInterruptEvent event) {
172        // iterate over the pin listeners map
173        for (Pin pin : listeners.keySet()) {
174            // dispatch this event to the listener 
175            // if a matching pin address is found
176            if (pin.getAddress() == event.getPin()) {
177                dispatchPinDigitalStateChangeEvent(pin, PinState.getState(event.getState()));
178            }            
179        }
180    }
181
182    @Override
183    public void addListener(Pin pin, PinListener listener) {
184        super.addListener(pin, listener);
185
186        // update the native interrupt listener thread for callbacks
187        updateInterruptListener(pin);        
188    }
189    
190    @Override
191    public void removeListener(Pin pin, PinListener listener) {
192        super.removeListener(pin, listener);
193        
194        // update the native interrupt listener thread for callbacks
195        updateInterruptListener(pin);        
196    }
197    
198    // internal 
199    private void updateInterruptListener(Pin pin) {
200        if (listeners.size() > 0) {
201            // setup interrupt listener native thread and enable callbacks
202            if (!com.pi4j.wiringpi.GpioInterrupt.hasListener(this)) {
203                com.pi4j.wiringpi.GpioInterrupt.addListener(this);
204            }
205            com.pi4j.wiringpi.GpioInterrupt.enablePinStateChangeCallback(pin.getAddress());
206        } else {
207            // remove interrupt listener, disable native thread and callbacks
208            com.pi4j.wiringpi.GpioInterrupt.disablePinStateChangeCallback(pin.getAddress());
209            if (com.pi4j.wiringpi.GpioInterrupt.hasListener(this)) {
210                com.pi4j.wiringpi.GpioInterrupt.removeListener(this);
211            }
212        }
213    }    
214}