001package jmri.jmrix.easydcc;
002
003import jmri.jmrix.AbstractMRListener;
004import jmri.jmrix.AbstractMRMessage;
005import jmri.jmrix.AbstractMRReply;
006import jmri.jmrix.AbstractMRTrafficController;
007import org.slf4j.Logger;
008import org.slf4j.LoggerFactory;
009
010/**
011 * Converts Stream-based I/O to/from EasyDcc messages. The "EasyDccInterface"
012 * side sends/receives message objects.
013 * <p>
014 * The connection to a EasyDccPortController is via a pair of *Streams, which
015 * then carry sequences of characters for transmission. Note that this
016 * processing is handled in an independent thread.
017 * <p>
018 * This handles the state transitions, based on the necessary state in each
019 * message.
020 * <p>
021 * Migrated for multiple connections, multi char connection prefix and Simulator.
022 *
023 * @author Bob Jacobsen Copyright (C) 2001
024 */
025public class EasyDccTrafficController extends AbstractMRTrafficController
026        implements EasyDccInterface {
027
028    /**
029     * Create a new EasyDccTrafficController instance.
030     *
031     * @param adaptermemo the associated SystemConnectionMemo
032     */
033    public EasyDccTrafficController(EasyDccSystemConnectionMemo adaptermemo) {
034        super();
035        mMemo = adaptermemo;
036        log.debug("creating a new EasyDccTrafficController object");
037    }
038
039    // Methods to implement the EasyDccInterface
040
041    @Override
042    public synchronized void addEasyDccListener(EasyDccListener l) {
043        this.addListener(l);
044    }
045
046    @Override
047    public synchronized void removeEasyDccListener(EasyDccListener l) {
048        this.removeListener(l);
049    }
050
051    /**
052     * Forward an EasyDccMessage to all registered EasyDccInterface listeners.
053     */
054    @Override
055    protected void forwardMessage(AbstractMRListener client, AbstractMRMessage m) {
056        ((EasyDccListener) client).message((EasyDccMessage) m);
057    }
058
059    /**
060     * Forward an EasyDccReply to all registered EasyDccInterface listeners.
061     */
062    @Override
063    protected void forwardReply(AbstractMRListener client, AbstractMRReply m) {
064        ((EasyDccListener) client).reply((EasyDccReply) m);
065    }
066
067    public void setSensorManager(jmri.SensorManager m) {
068    }
069
070    @Override
071    protected AbstractMRMessage pollMessage() {
072        return null;
073    }
074
075    @Override
076    protected AbstractMRListener pollReplyHandler() {
077        return null;
078    }
079
080    /**
081     * Forward a preformatted message to the actual interface.
082     */
083    @Override
084    public void sendEasyDccMessage(EasyDccMessage m, EasyDccListener reply) {
085        if (m == null) {
086            log.debug("empty message");
087            return;
088        }
089        log.debug("EasyDccTrafficController sendMessage() {}", m.toString());
090        sendMessage(m, reply);
091    }
092
093    @Override
094    protected AbstractMRMessage enterProgMode() {
095        return EasyDccMessage.getProgMode();
096    }
097
098    @Override
099    protected AbstractMRMessage enterNormalMode() {
100        return EasyDccMessage.getExitProgMode();
101    }
102
103    /**
104     * Reference to the system connection memo.
105     */
106    EasyDccSystemConnectionMemo mMemo = null;
107
108    /**
109     * Get access to the system connection memo associated with this traffic
110     * controller.
111     *
112     * @return associated systemConnectionMemo object
113     */
114    public EasyDccSystemConnectionMemo getSystemConnectionMemo() {
115        return mMemo;
116    }
117
118    /**
119     * Set the system connection memo associated with this traffic controller.
120     *
121     * @param m associated systemConnectionMemo object
122     */
123    public void setSystemConnectionMemo(EasyDccSystemConnectionMemo m) {
124        mMemo = m;
125    }
126
127    @Override
128    protected AbstractMRReply newReply() {
129        return new EasyDccReply();
130    }
131
132    @Override
133    protected boolean endOfMessage(AbstractMRReply msg) {
134        // note special case:  CV read / register read messages don't actually
135        // end until a P is received!
136        if ((msg.getElement(0) == 'C' && msg.getElement(1) == 'V') || (msg.getElement(0) == 'V')) {
137            // require the P
138            if ((msg.getNumDataElements() > 4) && msg.getElement(msg.getNumDataElements() - 2) != 'P') {
139                return false;
140            }
141        }
142        // detect that the reply buffer ends with "\n"
143        int index = msg.getNumDataElements() - 1;
144        if (msg.getElement(index) != 0x0d) {
145            return false;
146        } else {
147            return true;
148        }
149    }
150
151    /**
152     * Don't send to-normal-mode message if in normal mode
153     */
154    @Override
155    protected void terminate() {
156        if (mCurrentMode == NORMALMODE) {
157            log.debug("skipping sending normal mode during termination");
158            return;
159        } else {
160            super.terminate();
161        }
162    }
163    
164    private final static Logger log = LoggerFactory.getLogger(EasyDccTrafficController.class);
165
166}