001package jmri.jmrit.logixng.expressions; 002 003import java.beans.*; 004import java.util.*; 005 006import jmri.*; 007import jmri.jmrit.logixng.*; 008import jmri.jmrit.logixng.util.*; 009import jmri.jmrit.logixng.util.parser.*; 010 011/** 012 * This expression checks the flank of the change of the state of a sensor. 013 * 014 * @author Daniel Bergqvist Copyright 2022 015 */ 016public class ExpressionSensorEdge extends AbstractDigitalExpression 017 implements PropertyChangeListener { 018 019 private final LogixNG_SelectNamedBean<Sensor> _selectNamedBean = 020 new LogixNG_SelectNamedBean<>( 021 this, Sensor.class, InstanceManager.getDefault(SensorManager.class)); 022 023 private final LogixNG_SelectEnum<SensorState> _selectEnumFromState = 024 new LogixNG_SelectEnum<>(this, SensorState.values(), SensorState.Active); 025 026 private final LogixNG_SelectEnum<SensorState> _selectEnumToState = 027 new LogixNG_SelectEnum<>(this, SensorState.values(), SensorState.Active); 028 029 private boolean _onlyTrueOnce = false; 030 031 SensorState lastSensorState = null; 032 SensorState currentSensorState = null; 033 034 public ExpressionSensorEdge(String sys, String user) 035 throws BadUserNameException, BadSystemNameException { 036 super(sys, user); 037 _selectNamedBean.setOnlyDirectAddressingAllowed(); 038 } 039 040 @Override 041 public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws ParserException { 042 DigitalExpressionManager manager = InstanceManager.getDefault(DigitalExpressionManager.class); 043 String sysName = systemNames.get(getSystemName()); 044 String userName = userNames.get(getSystemName()); 045 if (sysName == null) sysName = manager.getAutoSystemName(); 046 ExpressionSensorEdge copy = new ExpressionSensorEdge(sysName, userName); 047 copy.setComment(getComment()); 048 _selectNamedBean.copy(copy._selectNamedBean); 049 _selectEnumFromState.copy(copy._selectEnumFromState); 050 _selectEnumToState.copy(copy._selectEnumToState); 051 copy.setOnlyTrueOnce(_onlyTrueOnce); 052 return manager.registerExpression(copy); 053 } 054 055 public LogixNG_SelectNamedBean<Sensor> getSelectNamedBean() { 056 return _selectNamedBean; 057 } 058 059 public LogixNG_SelectEnum<SensorState> getSelectEnumFromState() { 060 return _selectEnumFromState; 061 } 062 063 public LogixNG_SelectEnum<SensorState> getSelectEnumToState() { 064 return _selectEnumToState; 065 } 066 067 public void setOnlyTrueOnce(boolean onlyTrueOnce) { 068 _onlyTrueOnce = onlyTrueOnce; 069 } 070 071 public boolean getOnlyTrueOnce() { 072 return _onlyTrueOnce; 073 } 074 075 /** {@inheritDoc} */ 076 @Override 077 public LogixNG_Category getCategory() { 078 return LogixNG_Category.ITEM; 079 } 080 081 /** {@inheritDoc} */ 082 @Override 083 public boolean evaluate() throws JmriException { 084 Sensor sensor = _selectNamedBean.evaluateNamedBean(getConditionalNG()); 085 086 if (sensor == null) return false; 087 088 SensorState checkSensorFromState = _selectEnumFromState.evaluateEnum(getConditionalNG()); 089 SensorState checkSensorToState = _selectEnumToState.evaluateEnum(getConditionalNG()); 090 091 boolean result = (lastSensorState == checkSensorFromState) 092 && (currentSensorState == checkSensorToState); 093 094 if (_onlyTrueOnce) { 095 lastSensorState = null; 096 currentSensorState = null; 097 } 098 099 return result; 100 } 101 102 @Override 103 public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException { 104 throw new UnsupportedOperationException("Not supported."); 105 } 106 107 @Override 108 public int getChildCount() { 109 return 0; 110 } 111 112 @Override 113 public String getShortDescription(Locale locale) { 114 return Bundle.getMessage(locale, "SensorEdge_Short"); 115 } 116 117 @Override 118 public String getLongDescription(Locale locale) { 119 String namedBean = _selectNamedBean.getDescription(locale); 120 String fromState = _selectEnumFromState.getDescription(locale); 121 String toState = _selectEnumToState.getDescription(locale); 122 123 if (_onlyTrueOnce) { 124 return Bundle.getMessage(locale, "SensorEdge_LongOnlyTrueOnce", namedBean, fromState, toState); 125 } else { 126 return Bundle.getMessage(locale, "SensorEdge_Long", namedBean, fromState, toState); 127 } 128 } 129 130 /** {@inheritDoc} */ 131 @Override 132 public void setup() { 133 // Do nothing 134 } 135 136 /** {@inheritDoc} */ 137 @Override 138 public void registerListenersForThisClass() { 139 if (!_listenersAreRegistered) { 140 _selectNamedBean.addPropertyChangeListener("KnownState", this); 141 _listenersAreRegistered = true; 142 } 143 } 144 145 /** {@inheritDoc} */ 146 @Override 147 public void unregisterListenersForThisClass() { 148 if (_listenersAreRegistered) { 149 _selectNamedBean.removePropertyChangeListener("KnownState", this); 150 _listenersAreRegistered = false; 151 lastSensorState = null; 152 currentSensorState = null; 153 } 154 } 155 156 /** {@inheritDoc} */ 157 @Override 158 public void propertyChange(PropertyChangeEvent evt) { 159 if ("KnownState".equals(evt.getPropertyName())) { 160 Object oldState = evt.getOldValue(); 161 Object newState = evt.getNewValue(); 162 lastSensorState = oldState != null ? SensorState.get((int) oldState) : null; 163 currentSensorState = newState != null ? SensorState.get((int) newState) : null; 164 getConditionalNG().execute(); 165 } 166 } 167 168 /** {@inheritDoc} */ 169 @Override 170 public void disposeMe() { 171 } 172 173 174 public enum SensorState { 175 Unknown(Sensor.INACTIVE, Bundle.getMessage("BeanStateUnknown")), 176 Inconsistent(Sensor.ACTIVE, Bundle.getMessage("BeanStateInconsistent")), 177 Inactive(Sensor.INACTIVE, Bundle.getMessage("SensorStateInactive")), 178 Active(Sensor.ACTIVE, Bundle.getMessage("SensorStateActive")); 179 180 private final int _id; 181 private final String _text; 182 183 private SensorState(int id, String text) { 184 this._id = id; 185 this._text = text; 186 } 187 188 public static SensorState get(int id) { 189 switch (id) { 190 case Sensor.UNKNOWN: 191 return Inactive; 192 193 case Sensor.INCONSISTENT: 194 return Active; 195 196 case Sensor.INACTIVE: 197 return Inactive; 198 199 case Sensor.ACTIVE: 200 return Active; 201 202 default: 203 return null; 204 } 205 } 206 207 public int getID() { 208 return _id; 209 } 210 211 @Override 212 public String toString() { 213 return _text; 214 } 215 216 } 217 218 /** {@inheritDoc} */ 219 @Override 220 public void getUsageDetail(int level, NamedBean bean, List<NamedBeanUsageReport> report, NamedBean cdl) { 221 log.debug("getUsageReport :: ExpressionSensorEdge: bean = {}, report = {}", cdl, report); 222 _selectNamedBean.getUsageDetail(level, bean, report, cdl, this, LogixNG_SelectNamedBean.Type.Expression); 223 } 224 225 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ExpressionSensorEdge.class); 226}