001package jmri.jmrix.jmriclient; 002 003import jmri.Turnout; 004import jmri.implementation.AbstractTurnout; 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007 008/** 009 * JMRIClient implementation of the Turnout interface. 010 * 011 * @author Bob Jacobsen Copyright (C) 2001, 2008 012 * @author Paul Bender Copyright (C) 2010 013 */ 014public class JMRIClientTurnout extends AbstractTurnout implements JMRIClientListener { 015 016 // data members 017 private int _number; // turnout number 018 private JMRIClientTrafficController tc = null; 019 private String prefix = null; 020 private String transmitName = null; 021 022 /* Static arrays to hold Lenz specific feedback mode information */ 023 static String[] modeNames = null; 024 static int[] modeValues = null; 025 026 /** 027 * JMRIClient turnouts use the turnout number on the remote host. 028 * @param number turnout number 029 * @param memo system connection 030 */ 031 public JMRIClientTurnout(int number, JMRIClientSystemConnectionMemo memo) { 032 super(memo.getSystemPrefix() + "T" + number); 033 _number = number; 034 tc = memo.getJMRIClientTrafficController(); 035 prefix = memo.getSystemPrefix(); 036 transmitName = memo.getTransmitPrefix() + "T" + number; 037 /* allow monitoring mode feedback, which is the same 038 as direct for this connection (this aids the 039 transition from directly connected hardware to remotly 040 connected hardware.)*/ 041 _validFeedbackTypes |= MONITORING; 042 043 // Default feedback mode is MONITORING 044 _activeFeedbackType = MONITORING; 045 046 setModeInformation(_validFeedbackNames, _validFeedbackModes); 047 048 // set the mode names and values based on the static values. 049 _validFeedbackNames = getModeNames(); 050 _validFeedbackModes = getModeValues(); 051 052 // At construction, register for messages 053 tc.addJMRIClientListener(this); 054 // Then request status. 055 requestUpdateFromLayout(); 056 } 057 058 //Set the mode information for JMRIClient Turnouts. 059 synchronized static private void setModeInformation(String[] feedbackNames, int[] feedbackModes) { 060 // if it hasn't been done already, create static arrays to hold 061 // the JMRIClient specific feedback information. 062 if (modeNames == null) { 063 if (feedbackNames.length != feedbackModes.length) { 064 log.error("int and string feedback arrays different length"); 065 } 066 modeNames = new String[feedbackNames.length + 1]; 067 modeValues = new int[feedbackNames.length + 1]; 068 for (int i = 0; i < feedbackNames.length; i++) { 069 modeNames[i] = feedbackNames[i]; 070 modeValues[i] = feedbackModes[i]; 071 } 072 modeNames[feedbackNames.length] = "MONITORING"; 073 modeValues[feedbackNames.length] = MONITORING; 074 } 075 } 076 077 static int[] getModeValues() { 078 return modeValues; 079 } 080 081 static String[] getModeNames() { 082 return modeNames; 083 } 084 085 public int getNumber() { 086 return _number; 087 } 088 089 /** 090 * {@inheritDoc} 091 */ 092 @Override 093 protected void forwardCommandChangeToLayout(int newState) { 094 // sort out states 095 if ((newState & Turnout.CLOSED) != 0) { 096 // first look for the double case, which we can't handle 097 if ((newState & Turnout.THROWN) != 0) { 098 // this is the disaster case! 099 log.error("Cannot command both CLOSED and THROWN {}", newState); 100 return; 101 } else { 102 // send a CLOSED command 103 sendMessage(!getInverted()); 104 } 105 } else { 106 // send a THROWN command 107 sendMessage(getInverted()); 108 } 109 } 110 111 @Override 112 public boolean canInvert() { 113 return true; 114 } 115 116 // request a status update from the layout. 117 @Override 118 public void requestUpdateFromLayout() { 119 // create the message 120 String text = "TURNOUT " + transmitName + "\n"; 121 // create and send the message itself 122 tc.sendJMRIClientMessage(new JMRIClientMessage(text), this); 123 // This will handle ONESENSOR and TWOSENSOR feedback modes. 124 super.requestUpdateFromLayout(); 125 } 126 127 @Override 128 protected void turnoutPushbuttonLockout(boolean _pushButtonLockout) { 129 log.debug("Send command to {} Pushbutton {}{}", (_pushButtonLockout ? "Lock" : "Unlock"), prefix, _number); 130 } 131 132 protected void sendMessage(boolean closed) { 133 // get the message text 134 String text; 135 if (closed) { 136 text = "TURNOUT " + transmitName + " CLOSED\n"; 137 } else // thrown 138 { 139 text = "TURNOUT " + transmitName + " THROWN\n"; 140 } 141 142 // create and send the message itself 143 tc.sendJMRIClientMessage(new JMRIClientMessage(text), this); 144 } 145 146 // to listen for status changes from JMRIClient system 147 @Override 148 public void reply(JMRIClientReply m) { 149 String message = m.toString(); 150 if (!message.contains(transmitName + " ")) { 151 return; // not for us 152 } 153 if (m.toString().contains("THROWN")) { 154 newKnownState(!getInverted() ? jmri.Turnout.THROWN : jmri.Turnout.CLOSED); 155 } else if (m.toString().contains("CLOSED")) { 156 newKnownState(!getInverted() ? jmri.Turnout.CLOSED : jmri.Turnout.THROWN); 157 } else { 158 newKnownState(jmri.Turnout.UNKNOWN); 159 } 160 } 161 162 @Override 163 public void message(JMRIClientMessage m) { 164 } 165 166 private final static Logger log = LoggerFactory.getLogger(JMRIClientTurnout.class); 167 168}