001package jmri.jmrix.mrc;
002
003import java.util.Date;
004import jmri.NmraPacket;
005import jmri.Turnout;
006import jmri.implementation.AbstractTurnout;
007import org.slf4j.Logger;
008import org.slf4j.LoggerFactory;
009
010/**
011 * New MRC implementation of the Turnout interface From Xpa+Modem implementation
012 * of the Turnout interface.
013 *
014 * @author Paul Bender Copyright (C) 2004
015 * @author Martin Wade Copyright (C) 2014
016 * 
017 */
018public class MrcTurnout extends AbstractTurnout implements MrcTrafficListener {
019
020    // Private data member to keep track of what turnout we control.
021    int _number;
022    MrcTrafficController tc = null;
023    String prefix = "";
024
025    /**
026     * Mrc turnouts use any address allowed as an accessory decoder address on
027     * the particular command station.
028     * @param number turnout address value
029     * @param tc traffic controller for connection
030     * @param p system prefix for connection
031     */
032    public MrcTurnout(int number, MrcTrafficController tc, String p) {
033        super(p + "T" + number);
034        _number = number;
035        if (_number < NmraPacket.accIdLowLimit || _number > NmraPacket.accIdHighLimit) {
036            throw new IllegalArgumentException("Turnout value: " + _number 
037                    + " not in the range " + NmraPacket.accIdLowLimit + " to " 
038                    + NmraPacket.accIdHighLimit);
039        }
040        this.tc = tc;
041        this.prefix = p + "T";
042        tc.addTrafficListener(MrcInterface.TURNOUTS, this);
043    }
044
045    public int getNumber() {
046        return _number;
047    }
048
049    /**
050     * MRC turnouts can be inverted
051     */
052    @Override
053    public boolean canInvert() {
054        return true;
055    }
056
057    /**
058     * {@inheritDoc}
059     */
060    @Override
061    protected void forwardCommandChangeToLayout(int newState) {
062        // sort out states
063        if ((newState & Turnout.CLOSED) != 0) {
064            // first look for the double case, which we can't handle
065            if ((newState & Turnout.THROWN) != 0) {
066                // this is the disaster case!
067                log.error("Cannot command both CLOSED and THROWN {}", newState); // NOI18N
068                return;
069            } else {
070                // send a CLOSED command
071                forwardToCommandStation(!getInverted());
072            }
073        } else {
074            // send a THROWN command
075            forwardToCommandStation(getInverted());
076        }
077    }
078
079    void forwardToCommandStation(boolean state) {
080        MrcMessage m = null;
081        if (_number < 1000) {
082            m = MrcMessage.getSwitchMsg(_number, state);
083        } else {
084            m = MrcMessage.getRouteMsg((_number - 1000), state);
085        }
086        tc.sendMrcMessage(m);
087    }
088
089    @Override
090    public void notifyRcv(Date timestamp, MrcMessage m) {
091        if (m.getMessageClass() != MrcInterface.TURNOUTS) {
092            return;
093        }
094        if (m.getAccAddress() != getNumber()) {
095            if (m.getElement(0) == MrcPackets.ROUTECONTROLPACKETCMD) {
096                if ((m.getElement(4) + 1000) == getNumber()) {
097                    if (m.getElement(6) == 0x00) {
098                        newKnownState(jmri.Turnout.THROWN);
099                    } else if (m.getElement(6) == 0x80) {
100                        newKnownState(jmri.Turnout.CLOSED);
101                    } else {
102                        newKnownState(jmri.Turnout.UNKNOWN);
103                    }
104                }
105            }
106            return;
107        }
108        newKnownState(m.getAccState());
109    }
110
111    @Override
112    public void notifyXmit(Date timestamp, MrcMessage m) {/* message(m); */
113
114    }
115
116    @Override
117    public void notifyFailedXmit(Date timestamp, MrcMessage m) { /*message(m);*/ }
118
119    @Override
120    protected void turnoutPushbuttonLockout(boolean pushButtonLockout) {
121    }
122
123    private final static Logger log = LoggerFactory.getLogger(MrcTurnout.class);
124
125}