001package jmri.jmrix.lenz; 002 003import jmri.Sensor; 004import jmri.implementation.AbstractSensor; 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007 008/** 009 * Extend jmri.AbstractSensor for XpressNet layouts. 010 * 011 * @author Paul Bender Copyright (C) 2003-2010 012 */ 013public class XNetSensor extends AbstractSensor implements XNetListener { 014 015 private boolean statusRequested = false; 016 017 private int address; 018 private int baseaddress; /* The result of integer division of the 019 sensor address by 8 */ 020 021 private int nibble; /* Is this sensor in the upper or lower 022 nibble for the feedback encoder */ 023 024 private String systemName; 025 026 protected XNetTrafficController tc; 027 028 public XNetSensor(String systemName, String userName, XNetTrafficController controller, String prefix) { 029 super(systemName, userName); 030 tc = controller; 031 init(systemName, prefix); 032 } 033 034 public XNetSensor(String systemName, XNetTrafficController controller, String prefix) { 035 super(systemName); 036 tc = controller; 037 init(systemName, prefix); 038 } 039 040 /** 041 * Common initialization for all constructors. 042 * @param id System ID 043 * @param prefix System name prefix 044 */ 045 private void init(String id, String prefix) { 046 // store address 047 systemName = id; 048 address = XNetAddress.getBitFromSystemName(systemName, prefix); 049 // calculate the base address, the nibble, and the bit to examine 050 baseaddress = ((address - 1) / 8); 051 int temp = (address - 1) % 8; 052 if (temp < 4) { 053 // This address is in the lower nibble 054 nibble = 0x00; 055 } else { 056 nibble = 0x10; 057 } 058 if (log.isDebugEnabled()) { 059 log.debug("Created Sensor {} (Address {}, position {})", 060 systemName, baseaddress, 061 (((address - 1) % 8) + 1) 062 ); 063 } 064 // Finally, request the current state from the layout. 065 tc.getFeedbackMessageCache().requestCachedStateFromLayout(this); 066 } 067 068 /** 069 * Request an update on status by sending an XpressNet message. 070 */ 071 @Override 072 public void requestUpdateFromLayout() { 073 // To do this, we send an XpressNet Accessory Decoder Information 074 // Request. 075 // The generated message works for Feedback modules and turnouts 076 // with feedback, but the address passed is translated as though it 077 // is a turnout address. As a result, we substitute our base 078 // address in for the address. after the message is returned. 079 XNetMessage msg = XNetMessage.getFeedbackRequestMsg(baseaddress, 080 (nibble == 0x00)); 081 msg.setElement(1, baseaddress); 082 msg.setParity(); 083 synchronized (this) { 084 statusRequested = true; 085 } 086 tc.sendXNetMessage(msg, null); // The reply is treated as a broadcast 087 // and is returned using the manager. 088 } 089 090 /** 091 * initmessage is a package protected class which allows the Manger to send 092 * a feedback message at initialization without changing the state of the 093 * sensor with respect to whether or not a feedback request was sent. This 094 * is used only when the sensor is created by on layout feedback. 095 * @param l Reply message 096 */ 097 synchronized void initmessage(XNetReply l) { 098 boolean oldState = statusRequested; 099 message(l); 100 statusRequested = oldState; 101 } 102 103 /** 104 * Implementing classes will typically have a function/listener to get 105 * updates from the layout, which will then call public void 106 * firePropertyChange(String propertyName, Object oldValue, Object newValue) 107 * _once_ if anything has changed state (or set the commanded state 108 * directly) 109 * @param l Reply message 110 */ 111 @Override 112 public synchronized void message(XNetReply l) { 113 if (log.isDebugEnabled()) { 114 log.debug("received message: {}", l); 115 } 116 Boolean opt = l.selectModuleFeedback(address); 117 if (opt != null) { 118 if (log.isDebugEnabled()) { 119 log.debug("Message for sensor {} (Address {} position {})", systemName, baseaddress, address - (baseaddress * 8)); 120 } 121 if (opt ^ _inverted) { 122 setOwnState(Sensor.ACTIVE); 123 } else { 124 setOwnState(Sensor.INACTIVE); 125 } 126 } 127 } 128 129 /** 130 * Listen for the messages to the LI100/LI101. 131 * @param l message to process 132 */ 133 @Override 134 public void message(XNetMessage l) { 135 // not currently listening for outgoing messages. 136 } 137 138 /** 139 * Handle a timeout notification. 140 * @param msg The message that timed out 141 */ 142 @Override 143 public void notifyTimeout(XNetMessage msg) { 144 if (log.isDebugEnabled()) { 145 log.debug("Notified of timeout on message: {}", msg); 146 } 147 } 148 149 /** 150 * Package protected routine to get the Sensor Number. 151 * @return current Sensor address number 152 */ 153 int getNumber() { 154 return address; 155 } 156 157 /** 158 * Package protected routine to get the Sensor Base Address. 159 * @return the Sensor base address 160 */ 161 int getBaseAddress() { 162 return baseaddress; 163 } 164 165 /** 166 * Package protected routine to get the Sensor Nibble. 167 * @return contents of sensor nibble 168 */ 169 int getNibble() { 170 return nibble; 171 } 172 173 private static final Logger log = LoggerFactory.getLogger(XNetSensor.class); 174 175}