001package jmri.jmrix.lenz; 002 003import java.util.Locale; 004import javax.annotation.Nonnull; 005import jmri.Turnout; 006import org.slf4j.Logger; 007import org.slf4j.LoggerFactory; 008 009/** 010 * Implement turnout manager for Lenz (XpresssNet) connections. 011 * <p> 012 * System names are "XTnnn", where X is the user configurable system prefix, 013 * nnn is the turnout number without padding. 014 * 015 * @author Bob Jacobsen Copyright (C) 2001 016 * @author Paul Bender Copyright (C) 2003-2010 017 * @navassoc 1 - 1 jmri.jmrix.lenz.XNetProgrammer 018 */ 019public class XNetTurnoutManager extends jmri.managers.AbstractTurnoutManager implements XNetListener { 020 021 // ctor has to register for XNet events 022 public XNetTurnoutManager(XNetSystemConnectionMemo memo) { 023 super(memo); 024 tc = memo.getXNetTrafficController(); 025 // Force initialization, so it registers first and receives feedbacks before 026 // TurnoutManager autocreates turnout. 027 tc.getFeedbackMessageCache(); 028 tc.addXNetListener(XNetInterface.FEEDBACK, this); 029 } 030 031 protected XNetTrafficController tc; 032 033 /** 034 * {@inheritDoc} 035 */ 036 @Override 037 @Nonnull 038 public XNetSystemConnectionMemo getMemo() { 039 return (XNetSystemConnectionMemo) memo; 040 } 041 042 // XNet-specific methods 043 044 /** 045 * Create a new Turnout based on the system name. 046 * Assumes calling method has checked that a Turnout with this 047 * system name does not already exist. 048 * {@inheritDoc} 049 */ 050 @Nonnull 051 @Override 052 protected Turnout createNewTurnout(@Nonnull String systemName, String userName) throws IllegalArgumentException { 053 // check if the output bit is available 054 int bitNum = XNetAddress.getBitFromSystemName(systemName, getSystemPrefix()); 055 if (bitNum == -1) { 056 throw new IllegalArgumentException("Cannot get Bit from System Name " + systemName); 057 } 058 // create the new Turnout object 059 Turnout t = new XNetTurnout(getSystemPrefix(), bitNum, tc); 060 t.setUserName(userName); 061 return t; 062 } 063 064 /** 065 * Listen for turnouts, creating them as needed. 066 */ 067 @Override 068 public void message(XNetReply l) { 069 if (log.isDebugEnabled()) { 070 log.debug("received message: {}",l); 071 } 072 if (l.isFeedbackBroadcastMessage()) { 073 int numDataBytes = l.getElement(0) & 0x0f; 074 for (int i = 1; i < numDataBytes; i += 2) { 075 // parse message type 076 int addr = l.getTurnoutMsgAddr(i); 077 if (addr >= 0) { 078 log.debug("message has address: {}", addr); 079 // forward to the specified turnout. 080 String s = getSystemNamePrefix() + addr; 081 forwardMessageToTurnout(s, l); 082 if (addr % 2 != 0) { 083 // if the address is odd, also send the feedback 084 // message to the even turnout. 085 s = getSystemNamePrefix() + (addr + 1); 086 forwardMessageToTurnout(s, l); 087 } 088 } 089 } 090 } 091 } 092 093 protected void forwardMessageToTurnout(String s, XNetReply l){ 094 XNetTurnout t = (XNetTurnout) getBySystemName(s); 095 if ( null == t ) { 096 // need to create a new one, and send the message on 097 // to the newly created object. 098 ((XNetTurnout) provideTurnout(s)).initmessage(l); 099 } else { 100 // The turnout exists, forward this message to the 101 // turnout 102 t.message(l); 103 } 104 } 105 106 /** 107 * Get text to be used for the Turnout.CLOSED state in user communication. 108 * Allows text other than "CLOSED" to be use with certain hardware system to 109 * represent the Turnout.CLOSED state. 110 */ 111 @Override 112 @Nonnull 113 public String getClosedText() { 114 return Bundle.getMessage("TurnoutStateClosed"); 115 } 116 117 /** 118 * Get text to be used for the Turnout.THROWN state in user communication. 119 * Allows text other than "THROWN" to be use with certain hardware system to 120 * represent the Turnout.THROWN state. 121 */ 122 @Override 123 @Nonnull 124 public String getThrownText() { 125 return Bundle.getMessage("TurnoutStateThrown"); 126 } 127 128 // listen for the messages to the LI100/LI101 129 @Override 130 public void message(XNetMessage l) { 131 //this class does not currently use outgoing messages. 132 } 133 134 // Handle a timeout notification 135 @Override 136 public void notifyTimeout(XNetMessage msg) { 137 log.debug("Notified of timeout on message {}",msg); 138 } 139 140 /** 141 * {@inheritDoc} 142 */ 143 @Override 144 @Nonnull 145 public String validateSystemNameFormat(@Nonnull String name, @Nonnull Locale locale) { 146 return validateIntegerSystemNameFormat(name, 147 XNetAddress.MINSENSORADDRESS, 148 XNetAddress.MAXSENSORADDRESS, 149 locale); 150 } 151 152 /** 153 * {@inheritDoc} 154 */ 155 @Override 156 public NameValidity validSystemNameFormat(@Nonnull String systemName) { 157 return (XNetAddress.validSystemNameFormat(systemName, 'T', getSystemPrefix())); 158 } 159 160 @Override 161 public boolean allowMultipleAdditions(@Nonnull String systemName) { 162 return true; 163 } 164 165 /** 166 * {@inheritDoc} 167 */ 168 @Override 169 public String getEntryToolTip() { 170 return Bundle.getMessage("AddOutputEntryToolTip"); 171 } 172 173 private static final Logger log = LoggerFactory.getLogger(XNetTurnoutManager.class); 174 175}