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}