001 002package jmri.jmrix.pi; 003 004import com.pi4j.io.gpio.GpioController; 005import com.pi4j.io.gpio.GpioFactory; 006import com.pi4j.io.gpio.GpioPinDigitalInput; 007import com.pi4j.io.gpio.Pin; 008import com.pi4j.io.gpio.PinPullResistance; 009import com.pi4j.io.gpio.PinState; 010import com.pi4j.io.gpio.RaspiPin; 011import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent; 012import com.pi4j.io.gpio.event.GpioPinListenerDigital; 013 014import jmri.Sensor; 015import jmri.implementation.AbstractSensor; 016import jmri.jmrix.pi.simulator.GpioSimulator; 017 018import org.slf4j.Logger; 019import org.slf4j.LoggerFactory; 020 021/** 022 * Sensor interface for RaspberryPi GPIO pins. 023 * 024 * @author Paul Bender Copyright (C) 2003-2017 025 */ 026public class RaspberryPiSensor extends AbstractSensor implements GpioPinListenerDigital { 027 028 private static GpioController gpio = null; 029 private GpioPinDigitalInput pin = null; 030 private PinPullResistance pull = PinPullResistance.PULL_DOWN; 031 032 public RaspberryPiSensor(String systemName, String userName) { 033 super(systemName, userName); 034 // default pull is Pull Down 035 init(systemName, PinPullResistance.PULL_DOWN); 036 } 037 038 public RaspberryPiSensor(String systemName, String userName, PinPullResistance p) { 039 super(systemName, userName); 040 init(systemName, p); 041 } 042 043 public RaspberryPiSensor(String systemName) { 044 super(systemName); 045 init(systemName, PinPullResistance.PULL_DOWN); 046 } 047 048 public RaspberryPiSensor(String systemName, PinPullResistance p) { 049 super(systemName); 050 init(systemName, p); 051 } 052 053 /** 054 * Common initialization for all constructors. 055 * <p> 056 * Compare {@link RaspberryPiTurnout} 057 */ 058 private void init(String systemName, PinPullResistance pRes){ 059 log.debug("Provisioning sensor {}", systemName); 060 if (gpio == null) { 061 if (!RaspberryPiAdapter.isSimulator()) { 062 gpio = GpioFactory.getInstance(); 063 } else { 064 gpio = GpioSimulator.getInstance(); 065 } 066 } 067 pull = pRes; 068 int address = Integer.parseInt(systemName.substring(systemName.lastIndexOf("S") + 1)); 069 String pinName = "GPIO " + address; 070 Pin p = RaspiPin.getPinByName(pinName); 071 if (p != null) { 072 try { 073 pin = gpio.provisionDigitalInputPin(p, getSystemName(), pull); 074 } catch (java.lang.RuntimeException re) { 075 log.error("Provisioning sensor {} failed with: {}", systemName, re.getMessage()); 076 throw new IllegalArgumentException(re.getMessage()); 077 } 078 if (pin != null) { 079 pin.setShutdownOptions(true, PinState.LOW, PinPullResistance.OFF); 080 pin.addListener(this); 081 requestUpdateFromLayout(); // set state to match current value. 082 } else { 083 String msg = Bundle.getMessage("ProvisioningFailed", pinName, getSystemName()); 084 log.error(msg); 085 throw new IllegalArgumentException(msg); 086 } 087 } else { 088 String msg = Bundle.getMessage("PinNameNotValid", pinName, systemName); 089 log.error(msg); 090 throw new IllegalArgumentException(msg); 091 } 092 } 093 094 /** 095 * Request an update on status by sending an Instruction to the Pi. 096 */ 097 @Override 098 public void requestUpdateFromLayout() { 099 if (pin.isHigh()) 100 setOwnState(Sensor.ACTIVE); 101 else setOwnState(Sensor.INACTIVE); 102 } 103 104 @Override 105 public void dispose() { 106 try { 107 gpio.unprovisionPin(pin); 108 // will remove all listeners and triggers from pin and remove it from the <GpioPin> pins list in _gpio 109 } catch ( com.pi4j.io.gpio.exception.GpioPinNotProvisionedException npe ){ 110 log.trace("Pin not provisioned, was this sensor already disposed?"); 111 } 112 super.dispose(); 113 } 114 115 @Override 116 public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event){ 117 // log pin state change 118 log.debug("GPIO PIN STATE CHANGE: {} = {}", event.getPin(), event.getState()); 119 if (event.getPin() == pin){ 120 if (event.getState().isHigh()) { 121 setOwnState(!getInverted() ? Sensor.ACTIVE : Sensor.INACTIVE); 122 } else { 123 setOwnState(!getInverted() ? Sensor.INACTIVE : Sensor.ACTIVE); 124 } 125 } 126 } 127 128 /** 129 * Set the pull resistance on the pin. 130 * 131 * @param pr The new PinPullResistance value to set. 132 */ 133 private void setPullState(PinPullResistance pr){ 134 pull = pr; 135 pin.setPullResistance(pull); 136 } 137 138 /** 139 * Set the pull resistance. 140 * <p> 141 * In this default implementation, the input value is ignored. 142 * 143 * @param r PullResistance value to use. 144 */ 145 @Override 146 public void setPullResistance(PullResistance r){ 147 if (r == PullResistance.PULL_DOWN) { 148 setPullState(PinPullResistance.PULL_DOWN); 149 } else if(r == PullResistance.PULL_UP ) { 150 setPullState(PinPullResistance.PULL_UP); 151 } else { 152 setPullState(PinPullResistance.OFF); 153 } 154 } 155 156 /** 157 * Get the pull resistance 158 * 159 * @return the currently set PullResistance value. In this default 160 * implementation, PullResistance.PULL_OFF is always returned. 161 */ 162 @Override 163 public PullResistance getPullResistance(){ 164 if (pull == PinPullResistance.PULL_DOWN) { 165 return PullResistance.PULL_DOWN; 166 } else if(pull == PinPullResistance.PULL_UP) { 167 return PullResistance.PULL_UP; 168 } else { 169 return PullResistance.PULL_OFF; 170 } 171 } 172 173 private final static Logger log = LoggerFactory.getLogger(RaspberryPiSensor.class); 174 175}