001package jmri.jmrix.lenz; 002 003import jmri.implementation.AbstractLight; 004import org.slf4j.Logger; 005import org.slf4j.LoggerFactory; 006 007/** 008 * Implementation of the Light Object for XpressNet. 009 * <p> 010 * NOTE: This is a simplification of the XNetTurnout class. 011 * <p> 012 * Based in part on SerialLight.java 013 * 014 * @author Paul Bender Copyright (C) 2008-2010 015 */ 016public class XNetLight extends AbstractLight implements XNetListener { 017 018 private XNetTrafficController tc; 019 private XNetLightManager lm; 020 021 /** 022 * Create a Light object, with only system name. 023 * <p> 024 * 'systemName' was previously validated in LnLightManager 025 * 026 * @param tc the traffic controller for the connection 027 * @param lm the managing LightManager for this Light 028 * @param systemName the system name for this Light 029 */ 030 public XNetLight(XNetTrafficController tc, XNetLightManager lm, String systemName) { 031 super(systemName); 032 this.tc = tc; 033 this.lm = lm; 034 // Initialize the Light 035 initializeLight(systemName); 036 } 037 038 /** 039 * Create a Light object, with both system and user names. 040 * <p> 041 * 'systemName' was previously validated in XNetLightManager 042 * 043 * @param tc the traffic controller for the connection 044 * @param lm the managing LightManager for this Light 045 * @param systemName the system name for this Light 046 * @param userName the user name for this Light 047 */ 048 public XNetLight(XNetTrafficController tc, XNetLightManager lm, String systemName, String userName) { 049 super(systemName, userName); 050 this.tc = tc; 051 this.lm = lm; 052 // Initialize the Light 053 initializeLight(systemName); 054 } 055 056 /** 057 * Dispose of the light object. 058 */ 059 @Override 060 public void dispose() { 061 tc.removeXNetListener(XNetInterface.FEEDBACK | XNetInterface.COMMINFO | XNetInterface.CS_INFO, this); 062 super.dispose(); 063 } 064 065 /** 066 * Initialize the light object's parameters. 067 */ 068 private synchronized void initializeLight(String systemName) { 069 // Extract the Bit from the name 070 mAddress = lm.getBitFromSystemName(systemName); 071 // Set initial state 072 setState(OFF); 073 // At construction, register for messages 074 tc.addXNetListener(XNetInterface.FEEDBACK | XNetInterface.COMMINFO | XNetInterface.CS_INFO, this); 075 } 076 077 /* 078 * Set up system dependent instance variables and set system independent 079 * instance variables to default values. 080 * Note: most instance variables are in AbstractLight.java 081 */ 082 083 /** 084 * System dependent instance variables 085 */ 086 int mAddress = 0; // accessory output address 087 088 /** 089 * Internal State Machine states. 090 */ 091 static final int OFFSENT = 1; 092 static final int COMMANDSENT = 2; 093 static final int IDLE = 0; 094 private int internalState = IDLE; 095 096 /** 097 * Set the current state of this Light. This routine requests the hardware 098 * to change. 099 */ 100 @Override 101 synchronized public void setState(int newState) { 102 if (newState != ON && newState != OFF) { 103 // Unsuported state 104 log.warn("Unsupported state {} requested for light {}", newState, mSystemName); 105 return; 106 } 107 108 // get the right packet 109 XNetMessage msg = XNetMessage.getTurnoutCommandMsg(mAddress, 110 newState == ON, 111 newState == OFF, 112 true); 113 internalState = COMMANDSENT; 114 tc.sendXNetMessage(msg, this); 115 116 if (newState != mState) { 117 int oldState = mState; 118 mState = newState; 119 // notify listeners, if any 120 firePropertyChange("KnownState", oldState, newState); 121 } 122 sendOffMessage(); 123 } 124 125 /** 126 * Handle an incoming message from the XpressNet. NOTE: We aren't registered 127 * as a listener, so this is only triggered when we send out a message. 128 * 129 * @param l the message to handle 130 */ 131 @Override 132 synchronized public void message(XNetReply l) { 133 if (log.isDebugEnabled()) { 134 log.debug("received message: {}", l); 135 } 136 if (internalState == OFFSENT) { 137 // If an OFF was sent, we want to check for Communications 138 // errors before we try to do anything else. 139 if (l.isCommErrorMessage()) { 140 /* this is a communications error */ 141 log.error("Communications error occurred - message received was: {}", l); 142 sendOffMessage(); 143 } else if (l.isCSBusyMessage()) { 144 /* this is a communications error */ 145 log.error("Command station busy - message received was: {}", l); 146 sendOffMessage(); 147 } else if (l.isOkMessage()) { 148 /* the command was successfully received */ 149 internalState = IDLE; 150 } else if (internalState == COMMANDSENT) { 151 // If command was sent,, we want to check for Communications 152 // errors before we try to do anything else. 153 if (l.isCommErrorMessage()) { 154 /* this is a communications error */ 155 log.error("Communications error occurred - message received was: {}", l); 156 setState(mState); 157 } else if (l.isCSBusyMessage()) { 158 /* this is a communications error */ 159 log.error("Command station busy - message received was: {}", l); 160 setState(mState); 161 } else if (l.isOkMessage()) { 162 /* the command was successfully received */ 163 sendOffMessage(); 164 } 165 } 166 } 167 } 168 169 /** 170 * Listen for the messages to the LI100/LI101. 171 * 172 * @param l the expected message 173 */ 174 @Override 175 public void message(XNetMessage l) { 176 } 177 178 // Handle a timeout notification 179 @Override 180 public void notifyTimeout(XNetMessage msg) { 181 if (log.isDebugEnabled()) { 182 log.debug("Notified of timeout on message{}", msg.toString()); 183 } 184 } 185 186 /** 187 * Send an "Off" message to the decoder for this output. 188 */ 189 private synchronized void sendOffMessage() { 190 // We need to tell the turnout to shut off the output. 191 if (log.isDebugEnabled()) { 192 log.debug("Sending off message for light {} commanded state= {}", mAddress, mState); 193 } 194 XNetMessage msg = XNetMessage.getTurnoutCommandMsg(mAddress, 195 mState == ON, 196 mState == OFF, 197 false); 198 tc.sendXNetMessage(msg, this); 199 200 // Set the known state to the commanded state. 201 internalState = OFFSENT; 202 } 203 204 private static final Logger log = LoggerFactory.getLogger(XNetLight.class); 205 206}