001package jmri.jmrix.dccpp; 002 003import jmri.Sensor; 004import jmri.implementation.AbstractSensor; 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007 008import javax.annotation.concurrent.GuardedBy; 009 010/** 011 * Extend jmri.AbstractSensor for DCC++ layouts. 012 * 013 * @author Paul Bender Copyright (C) 2003-2010 014 * @author Mark Underwood Copyright (C) 2015 015 * 016 * Based on XNetSensor 017 */ 018public class DCCppSensor extends AbstractSensor implements DCCppListener { 019 020 private boolean statusRequested = false; 021 022 private int address; // NOTE: For DCC++ this is the Base Station index # 023 //private int baseaddress; /* The result of integer division of the 024 // sensor address by 8 */ 025 026 @GuardedBy("this") 027 private int pin; 028 @GuardedBy("this") 029 private boolean pullup; 030 031 //private int nibble; /* Is this sensor in the upper or lower 032 //nibble for the feedback encoder */ 033 034 private String systemName; 035 036 protected DCCppTrafficController tc; 037 038 public DCCppSensor(String systemName, String userName, DCCppTrafficController controller) { 039 super(systemName, userName); 040 tc = controller; 041 init(systemName); 042 } 043 044 public DCCppSensor(String systemName, DCCppTrafficController controller) { 045 super(systemName); 046 tc = controller; 047 init(systemName); 048 } 049 050 public synchronized boolean getPullup() { return(pullup); } 051 public synchronized int getPin() { return(pin); } 052 public int getIndex() { return(address); } 053 054 /** 055 * Common initialization for both constructors 056 */ 057 private void init(String id) { 058 // store address 059 systemName = id; 060 //prefix = jmri.InstanceManager.getDefault(jmri.jmrix.dccpp.DCCppSensorManager.class).getSystemPrefix(); 061 address = Integer.parseInt(id.substring(id.lastIndexOf('S') + 1)); 062 log.debug("New sensor system name {} address {}", this.getSystemName(), address); 063 log.debug("Created Sensor {}", systemName); 064 // Finally, request the current state from the layout. 065 //this.requestUpdateFromLayout(); 066 //tc.getFeedbackMessageCache().requestCachedStateFromLayout(this); 067 068 } 069 070 /** 071 * request an update on status by sending a DCC++ message 072 */ 073 @Override 074 public void requestUpdateFromLayout() { 075 // Yeah... this isn't really supported. Yet. 076 // 077 // To do this, we send an DCC++ Accessory Decoder Information 078 // Request. 079 // The generated message works for Feedback modules and turnouts 080 // with feedback, but the address passed is translated as though it 081 // is a turnout address. As a result, we substitute our base 082 // address in for the address. after the message is returned. 083 /* 084 DCCppMessage msg = DCCppMessage.getFeedbackRequestMsg(baseaddress, 085 (nibble == 0x00)); 086 msg.setElement(1, baseaddress); 087 msg.setParity(); 088 synchronized (this) { 089 statusRequested = true; 090 } 091 tc.sendDCCppMessage(msg, null); // The reply is treated as a broadcast 092 // and is returned using the manager. 093 */ 094 } 095 096 /** 097 * initmessage is a package protected class which allows the Manger to send 098 * a feedback message at initialization without changing the state of the 099 * sensor with respect to whether or not a feedback request was sent. This 100 * is used only when the sensor is created by on layout feedback. 101 * @param l Init message 102 */ 103 synchronized void initmessage(DCCppReply l) { 104 boolean oldState = statusRequested; 105 message(l); 106 statusRequested = oldState; 107 } 108 109 /** 110 * {@inheritDoc} 111 * implementing classes will typically have a function/listener to get 112 * updates from the layout, which will then call public void 113 * firePropertyChange(String propertyName, Object oldValue, Object newValue) 114 * _once_ if anything has changed state (or set the commanded state 115 * directly) 116 */ 117 @Override 118 public synchronized void message(DCCppReply l) { 119 if (l.isSensorDefReply()) { 120 log.debug("Sensor Def Reply received: '{}'", l); 121 if (l.getSensorDefNumInt() == address) { 122 log.debug("Def Message for sensor {} (Pin {})", systemName, address); 123 setOwnState(Sensor.UNKNOWN); 124 l.getProperties().forEach((key, value) -> { 125 this.setProperty(key, value); //copy the defining properties from message to sensor 126 }); 127 } 128 } else if (l.isSensorReply() && (l.getSensorNumInt() == address)) { 129 log.debug("Message for sensor {} (Pin {})", systemName, address); 130 if (l.getSensorIsActive()) { 131 setOwnState(_inverted ? Sensor.INACTIVE : Sensor.ACTIVE); 132 } else if (l.getSensorIsInactive()){ 133 setOwnState(_inverted ? Sensor.ACTIVE : Sensor.INACTIVE); 134 } else { 135 setOwnState(Sensor.UNKNOWN); 136 } 137 } 138 } 139 140 /** 141 * {@inheritDoc} 142 * Listen for the messages to the Base Station... but ignore them. 143 * 144 * @param l the message heard 145 */ 146 @Override 147 public void message(DCCppMessage l) { 148 } 149 150 // Handle a timeout notification 151 @Override 152 public void notifyTimeout(DCCppMessage msg) { 153 log.debug("Notified of timeout on message '{}'", msg); 154 } 155 156 @Override 157 public void dispose() { 158 super.dispose(); 159 } 160 161 // package protected routine to get the Sensor Number 162 int getNumber() { 163 return address; 164 } 165 166 // package protected routine to get the Sensor Base Address 167 int getBaseAddress() { 168 //return baseaddress; 169 return(address); 170 } 171 172 // package protected routine to get the Sensor Nibble 173 int getNibble() { 174 //return nibble; 175 return(0); 176 } 177 178 private final static Logger log = LoggerFactory.getLogger(DCCppSensor.class); 179 180}