001package jmri.jmrix.can.adapters.lawicell;
002
003import jmri.jmrix.AbstractMRListener;
004import jmri.jmrix.AbstractMRMessage;
005import jmri.jmrix.AbstractMRReply;
006import jmri.jmrix.can.CanListener;
007import jmri.jmrix.can.CanMessage;
008import jmri.jmrix.can.CanReply;
009import org.slf4j.Logger;
010import org.slf4j.LoggerFactory;
011
012/**
013 * Traffic controller for the LAWICELL protocol.
014 * <p>
015 * Lawicell adapters use messages transmitted as an ASCII string of up to 24
016 * characters of the form: ;ShhhhNd0d1d2d3d4d5d6d7: The S indicates a standard
017 * CAN frame hhhh is the two byte header N or R indicates a normal or remote
018 * frame d0 - d7 are the (up to) 8 data bytes
019 *
020 * @author Andrew Crosland Copyright (C) 2008
021 * @author Bob Jacobsen Copyright (C) 2008
022 */
023public class LawicellTrafficController extends jmri.jmrix.can.TrafficController {
024
025    public LawicellTrafficController() {
026        super();
027    }
028
029    /**
030     * Forward a CanMessage to all registered CanInterface listeners.
031     */
032    @Override
033    protected void forwardMessage(AbstractMRListener client, AbstractMRMessage m) {
034        ((CanListener) client).message((CanMessage) m);
035    }
036
037    /**
038     * Forward a CanReply to all registered CanInterface listeners.
039     * {@inheritDoc}
040     */
041    @Override
042    protected void forwardReply(AbstractMRListener client, AbstractMRReply r) {
043        ((CanListener) client).reply((CanReply) r);
044    }
045
046    // Current state
047    public static final int NORMAL = 0;
048    public static final int BOOTMODE = 1;
049
050    public int getgcState() {
051        return gcState;
052    }
053
054    public void setgcState(int s) {
055        gcState = s;
056        log.debug("Setting gcState {}",s);
057    }
058
059    public boolean isBootMode() {
060        return gcState == BOOTMODE;
061    }
062
063    /**
064     * Forward a preformatted message to the actual interface.
065     * {@inheritDoc}
066     */
067    @Override
068    public void sendCanMessage(CanMessage m, CanListener reply) {
069        log.debug("TrafficController sendCanMessage() {}", m.toString());
070        sendMessage(m, reply);
071    }
072
073    /**
074     * Forward a preformatted reply to the actual interface.
075     * {@inheritDoc}
076     */
077    @Override
078    public void sendCanReply(CanReply r, CanListener reply) {
079        log.debug("TrafficController sendCanReply() {}", r.toString());
080        notifyReply(r, reply);
081    }
082
083    /**
084     * Add trailer to the outgoing byte stream.
085     *
086     * @param msg    The output byte stream
087     * @param offset the first byte not yet used
088     */
089    @Override
090    protected void addTrailerToOutput(byte[] msg, int offset, AbstractMRMessage m) {
091    }
092
093    /**
094     * Determine how much many bytes the entire message will take, including
095     * space for header and trailer
096     *
097     * @param m The message to be sent
098     * @return Number of bytes
099     */
100    @Override
101    protected int lengthOfByteStream(AbstractMRMessage m) {
102        return m.getNumDataElements();
103    }
104
105    // New message for hardware protocol
106    @Override
107    protected AbstractMRMessage newMessage() {
108        log.debug("New Message created");
109        Message msg = new Message();
110        return msg;
111    }
112
113    /**
114     * Make a CanReply from a Lawicell-specific reply.
115     * {@inheritDoc}
116     */
117    @Override
118    public CanReply decodeFromHardware(AbstractMRReply m) {
119        log.debug("Decoding from hardware: {}", m );
120        CanReply ret = new CanReply();
121        try {
122            Reply gc = (Reply) m;
123            ret = gc.createReply();
124            log.debug("Decoded {} as {} ",gc,ret);
125        } catch (java.lang.ClassCastException cce){
126                log.error("Unable to cast Reply {}",m);
127        }
128        return ret;
129    }
130
131    /**
132     * Encode a CanMessage into Lawicell format for the hardware.
133     * {@inheritDoc}
134     */
135    @Override
136    public AbstractMRMessage encodeForHardware(CanMessage m) {
137        Message ret = new Message(m);
138        log.debug("Encoding for hardware as {}",ret);
139        return ret;
140    }
141
142    // New reply from hardware
143    @Override
144    protected AbstractMRReply newReply() {
145        log.debug("New Reply created");
146        Reply reply = new Reply();
147        return reply;
148    }
149
150    /**
151     * Normal Lawicell replies will end with CR; errors are BELL.
152     * {@inheritDoc}
153     */
154    @Override
155    protected boolean endOfMessage(AbstractMRReply r) {
156        return endNormalReply(r);
157    }
158
159    boolean endNormalReply(AbstractMRReply r) {
160        // Detect if the reply buffer ends with bell or cr
161        int num = r.getNumDataElements() - 1;
162        if (r.getElement(num) == 0x0D) {
163            return true;
164        }
165        return r.getElement(num) == 0x07;
166    }
167
168    private int gcState;
169
170    private final static Logger log = LoggerFactory.getLogger(LawicellTrafficController.class);
171}