001package jmri.jmrix.sprog; 002 003import jmri.NmraPacket; 004import jmri.Turnout; 005import jmri.implementation.AbstractTurnout; 006import org.slf4j.Logger; 007import org.slf4j.LoggerFactory; 008 009/** 010 * Sprog implementation of the Turnout interface. 011 * <p> 012 * This object doesn't listen to the Sprog 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, 2003, 2005 017 * @author J.M. (Mark) Knox Copyright (C) 2005 018 */ 019public class SprogTurnout extends AbstractTurnout { 020 021 private SprogSystemConnectionMemo _memo = null; 022 023 /** 024 * Create a SPROG Turnout object. 025 * <p> 026 * Sprog turnouts use the NMRA number (0-511) as their numerical 027 * identification. 028 * @param number NMRA number 029 * @param memo system connection 030 */ 031 public SprogTurnout(int number, SprogSystemConnectionMemo memo) { 032 super(memo.getSystemPrefix() + "T" + number); 033 _number = number; 034 _memo = memo; 035 } 036 037 public int getNumber() { 038 return _number; 039 } 040 041 /** 042 * {@inheritDoc} 043 */ 044 @Override 045 protected void forwardCommandChangeToLayout(int newState) { 046 // sort out states 047 if ((newState & Turnout.CLOSED) != 0) { 048 // first look for the double case, which we can't handle 049 if ((newState & Turnout.THROWN) != 0) { 050 // this is the disaster case! 051 log.error("Cannot command both CLOSED and THROWN {}", newState); 052 return; 053 } else { 054 // send a CLOSED command 055 sendMessage(true ^ getInverted()); 056 } 057 } else { 058 // send a THROWN command 059 sendMessage(false ^ getInverted()); 060 } 061 } 062 063 @Override 064 protected void turnoutPushbuttonLockout(boolean _pushButtonLockout) { 065 if (log.isDebugEnabled()) { 066 log.debug("Send command to {} Pushbutton {}T{}", 067 (_pushButtonLockout ? "Lock" : "Unlock"), 068 _memo.getSystemPrefix(), 069 _number); 070 } 071 } 072 073 // data members 074 int _number; // turnout number 075 076 protected void sendMessage(boolean closed) { 077 // get the packet 078 byte[] bl = NmraPacket.accDecoderPkt(_number, closed); 079 if (log.isDebugEnabled()) { 080 log.debug("packet: {} {} {}", 081 Integer.toHexString(0xFF & bl[0]), 082 Integer.toHexString(0xFF & bl[1]), 083 Integer.toHexString(0xFF & bl[2])); 084 } 085 086 SprogMessage m = new SprogMessage(10); 087 int i = 0; // counter to make it easier to format the message 088 m.setElement(i++, 'O'); // "S02 " means send it twice 089 m.setElement(i++, ' '); 090 // m.setElement(i++, '2'); // not required? 091 String s = Integer.toHexString(bl[0] & 0xFF).toUpperCase(); 092 if (s.length() == 1) { 093 m.setElement(i++, '0'); 094 m.setElement(i++, s.charAt(0)); 095 } else { 096 m.setElement(i++, s.charAt(0)); 097 m.setElement(i++, s.charAt(1)); 098 } 099 m.setElement(i++, ' '); 100 s = Integer.toHexString(bl[1] & 0xFF).toUpperCase(); 101 if (s.length() == 1) { 102 m.setElement(i++, '0'); 103 m.setElement(i++, s.charAt(0)); 104 } else { 105 m.setElement(i++, s.charAt(0)); 106 m.setElement(i++, s.charAt(1)); 107 } 108 m.setElement(i++, ' '); 109 s = Integer.toHexString(bl[2] & 0xFF).toUpperCase(); 110 if (s.length() == 1) { 111 m.setElement(i++, '0'); 112 m.setElement(i++, s.charAt(0)); 113 } else { 114 m.setElement(i++, s.charAt(0)); 115 m.setElement(i++, s.charAt(1)); 116 } 117 118 _memo.getSprogTrafficController().sendSprogMessage(m, null); 119 } 120 121 @Override 122 public boolean canInvert() { 123 return true; 124 } 125 126 private final static Logger log = LoggerFactory.getLogger(SprogTurnout.class); 127 128}