001package jmri.jmrix.tmcc;
002
003import jmri.Turnout;
004import jmri.implementation.AbstractTurnout;
005import org.slf4j.Logger;
006import org.slf4j.LoggerFactory;
007
008/**
009 * Extend jmri.AbstractTurnout for TMCC serial layouts.
010 * <p>
011 * This object doesn't listen to the TMCC communications. This is because it
012 * should be the only object that is sending messages for this turnout; more
013 * than one Turnout object pointing to a single device is not allowed.
014 *
015 * @author Bob Jacobsen Copyright (C) 2003, 2006
016 */
017public class SerialTurnout extends AbstractTurnout {
018
019    // data members
020    int _number; // turnout number
021    private SerialTrafficController tc = null;
022    protected String _prefix = "T"; // default to "T"
023
024    /**
025     * Create a turnout. TMCC turnouts use the number 1-99 as their
026     * numerical identification. The TMCC SC-2 reserves 0 as a special reset
027     * address, but the TMCC SC-1 allows 0 to be a turnout; however, the SC-1
028     * documentation examples and callouts all use 1 as the first turnout
029     * address.
030     *
031     * @param prefix the connection prefix
032     * @param number the TMCC turnout number from 1 to 99
033     * @param memo   the connection memo
034     */
035    public SerialTurnout(String prefix, int number, TmccSystemConnectionMemo memo) {
036        super(prefix + "T" + number);
037        tc = memo.getTrafficController();
038        _number = number;
039        _prefix = prefix;
040        // At construction, don't register for messages (see package doc)
041    }
042
043    /**
044     * {@inheritDoc}
045     */
046    @Override
047    protected void forwardCommandChangeToLayout(int newState) {
048
049        // sort out states
050        if ((newState & Turnout.CLOSED) != 0) {
051            // first look for the double case, which we can't handle
052            if ((newState & Turnout.THROWN) != 0) {
053                // this is the disaster case!
054                log.error("Cannot command both CLOSED and THROWN {}", newState);
055                return;
056            } else {
057                // send a CLOSED command
058                sendMessage(true ^ getInverted());
059            }
060        } else {
061            // send a THROWN command
062            sendMessage(false ^ getInverted());
063        }
064    }
065
066    @Override
067    protected void turnoutPushbuttonLockout(boolean _pushButtonLockout) {
068        if (log.isDebugEnabled()) {
069            log.debug("Send command to {} Pushbutton {}T{}", (_pushButtonLockout ? "Lock" : "Unlock"), _prefix, _number);
070        }
071    }
072
073    protected void sendMessage(boolean closed) {
074        SerialMessage m = new SerialMessage();
075        m.setOpCode(0xFE);
076        if (closed) {
077            m.putAsWord(0x4000 + _number * 128);
078        } else {
079            m.putAsWord(0x401F + _number * 128);
080        }
081        tc.sendSerialMessage(m, null);
082        tc.sendSerialMessage(m, null);
083        tc.sendSerialMessage(m, null);
084        tc.sendSerialMessage(m, null);
085    }
086
087    private final static Logger log = LoggerFactory.getLogger(SerialTurnout.class);
088
089}