001package jmri.jmrix.oaktree;
002
003import jmri.Turnout;
004import jmri.implementation.AbstractTurnout;
005import org.slf4j.Logger;
006import org.slf4j.LoggerFactory;
007
008/**
009 * Extend jmri.AbstractTurnout for Oak Tree serial layouts.
010 *
011 * This object doesn't listen to the Oak Tree serial communications. This is
012 * because it should be the only object that is sending messages for this
013 * turnout; more than one Turnout object pointing to a single device is not
014 * allowed.
015 *
016 * @author Bob Jacobsen Copyright (C) 2003, 2006
017 */
018public class SerialTurnout extends AbstractTurnout {
019
020    private OakTreeSystemConnectionMemo _memo = null;
021
022    /**
023     * Create a Turnout object, with both system and user names.
024     * <p>
025     * 'systemName' was previously validated in SerialTurnoutManager
026     * @param systemName turnout system name
027     * @param userName turnout user name
028     * @param memo system connection
029     */
030    public SerialTurnout(String systemName, String userName, OakTreeSystemConnectionMemo memo) {
031        super(systemName, userName);
032        // Save system Name
033        tSystemName = systemName;
034        _memo = memo;
035        // Extract the Bit from the name
036        tBit = SerialAddress.getBitFromSystemName(systemName, _memo.getSystemPrefix());
037    }
038
039    /**
040     * {@inheritDoc}
041     */
042    @Override
043    protected void forwardCommandChangeToLayout(int newState) {
044        // implementing classes will typically have a function/listener to get
045        // updates from the layout, which will then call
046        //  public void firePropertyChange(String propertyName,
047        //                    Object oldValue,
048        //      Object newValue)
049        // _once_ if anything has changed state (or set the commanded state directly)
050
051        // sort out states
052        if ((newState & Turnout.CLOSED) != 0) {
053            // first look for the double case, which we can't handle
054            if ((newState & Turnout.THROWN) != 0) {
055                // this is the disaster case!
056                log.error("Cannot command both CLOSED and THROWN {}", newState);
057                return;
058            } else {
059                // send a CLOSED command
060                sendMessage(!getInverted());
061            }
062        } else {
063            // send a THROWN command
064            sendMessage(getInverted());
065        }
066    }
067
068    @Override
069    protected void turnoutPushbuttonLockout(boolean _pushButtonLockout) {
070        log.debug("Send command to {} Pushbutton", (_pushButtonLockout ? "Lock" : "Unlock"));
071    }
072
073    // data members
074    String tSystemName; // System Name of this turnout
075    int tBit;          // bit number of turnout control in Serial node
076
077    protected void sendMessage(boolean closed) {
078        SerialNode tNode = SerialAddress.getNodeFromSystemName(tSystemName, _memo.getTrafficController());
079        if (tNode == null) {
080            // node does not exist, ignore call
081            return;
082        }
083        tNode.setOutputBit(tBit, closed);
084    }
085
086    private final static Logger log = LoggerFactory.getLogger(SerialTurnout.class);
087
088}