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