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}