001package jmri.jmrix.easydcc; 002 003import jmri.NmraPacket; 004import jmri.Turnout; 005import jmri.implementation.AbstractTurnout; 006import org.slf4j.Logger; 007import org.slf4j.LoggerFactory; 008 009/** 010 * EasyDCC implementation of the Turnout interface. 011 * <p> 012 * This object doesn't listen to the EasyDcc communications. This is because it 013 * should be the only object that is sending messages for this turnout; more 014 * than one Turnout object pointing to a single device is not allowed. 015 * 016 * @author Bob Jacobsen Copyright (C) 2001 017 */ 018public class EasyDccTurnout extends AbstractTurnout { 019 020 // data members 021 int _number; // turnout number 022 private EasyDccTrafficController tc = null; 023 protected String _prefix = "E"; // default to "E" 024 025 /** 026 * Create a turnout. 027 * <p> 028 * EasyDCC turnouts use the NMRA number (0-2044) as their numerical identification. 029 * 030 * @param prefix system connection prefix 031 * @param number the NMRA turnout number from 0 to 2044 032 * @param memo system connection 033 */ 034 public EasyDccTurnout(String prefix, int number, EasyDccSystemConnectionMemo memo) { 035 super(prefix + "T" + number); 036 tc = memo.getTrafficController(); 037 _number = number; 038 _prefix = prefix; 039 // At construction, don't register for messages (see package doc) 040 } 041 042 public int getNumber() { 043 return _number; 044 } 045 046 // Turnouts do support inversion 047 @Override 048 public boolean canInvert() { 049 return true; 050 } 051 052 /** 053 * {@inheritDoc} 054 */ 055 @Override 056 protected void forwardCommandChangeToLayout(int newState) { 057 // sort out states 058 if ((newState & Turnout.CLOSED) != 0) { 059 // first look for the double case, which we can't handle 060 if ((newState & Turnout.THROWN) != 0) { 061 // this is the disaster case! 062 log.error("Cannot command both CLOSED and THROWN {}", newState); 063 } else { 064 // send a CLOSED command 065 sendMessage(true ^ getInverted()); 066 } 067 } else { 068 // send a THROWN command 069 sendMessage(false ^ getInverted()); 070 } 071 } 072 073 @Override 074 protected void turnoutPushbuttonLockout(boolean _pushButtonLockout) { 075 log.debug("Send command to {} Pushbutton {}T{}", 076 (_pushButtonLockout ? "Lock" : "Unlock"), _prefix, _number); 077 } 078 079 protected void sendMessage(boolean closed) { 080 // get the packet 081 byte[] bl = NmraPacket.accDecoderPkt(_number, closed); 082 if (log.isDebugEnabled()) { 083 log.debug("packet: {} {} {}", Integer.toHexString(0xFF & bl[0]), Integer.toHexString(0xFF & bl[1]), Integer.toHexString(0xFF & bl[2])); 084 } 085 086 EasyDccMessage m = new EasyDccMessage(13); 087 int i = 0; // counter to make it easier to format the message 088 m.setElement(i++, 'S'); // "S02 " means send it twice 089 m.setElement(i++, ' '); 090 m.setElement(i++, '0'); 091 m.setElement(i++, '2'); 092 m.setElement(i++, ' '); 093 String s = Integer.toHexString(bl[0] & 0xFF).toUpperCase(); 094 if (s.length() == 1) { 095 m.setElement(i++, '0'); 096 m.setElement(i++, s.charAt(0)); 097 } else { 098 m.setElement(i++, s.charAt(0)); 099 m.setElement(i++, s.charAt(1)); 100 } 101 s = Integer.toHexString(bl[1] & 0xFF).toUpperCase(); 102 m.setElement(i++, ' '); 103 if (s.length() == 1) { 104 m.setElement(i++, '0'); 105 m.setElement(i++, s.charAt(0)); 106 } else { 107 m.setElement(i++, s.charAt(0)); 108 m.setElement(i++, s.charAt(1)); 109 } 110 s = Integer.toHexString(bl[2] & 0xFF).toUpperCase(); 111 m.setElement(i++, ' '); 112 if (s.length() == 1) { 113 m.setElement(i++, '0'); 114 m.setElement(i++, s.charAt(0)); 115 } else { 116 m.setElement(i++, s.charAt(0)); 117 m.setElement(i++, s.charAt(1)); 118 } 119 120 log.debug("send easydcc message for turnout {}T{}", _prefix, _number); 121 tc.sendEasyDccMessage(m, null); 122 } 123 124 private final static Logger log = LoggerFactory.getLogger(EasyDccTurnout.class); 125 126}