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     */
040    @Override
041    protected void forwardReply(AbstractMRListener client, AbstractMRReply r) {
042        ((CanListener) client).reply((CanReply) r);
043    }
044
045    // Current state
046    public static final int NORMAL = 0;
047    public static final int BOOTMODE = 1;
048
049    public int getgcState() {
050        return gcState;
051    }
052
053    public void setgcState(int s) {
054        gcState = s;
055        log.debug("Setting gcState {}",s);
056    }
057
058    public boolean isBootMode() {
059        return gcState == BOOTMODE;
060    }
061
062    /**
063     * Forward a preformatted message to the actual interface.
064     */
065    @Override
066    public void sendCanMessage(CanMessage m, CanListener reply) {
067        log.debug("TrafficController sendCanMessage() {}", m.toString());
068        sendMessage(m, reply);
069    }
070
071    /**
072     * Forward a preformatted reply to the actual interface.
073     */
074    @Override
075    public void sendCanReply(CanReply r, CanListener reply) {
076        log.debug("TrafficController sendCanReply() {}", r.toString());
077        notifyReply(r, reply);
078    }
079
080    /**
081     * Add trailer to the outgoing byte stream.
082     *
083     * @param msg    The output byte stream
084     * @param offset the first byte not yet used
085     */
086    @Override
087    protected void addTrailerToOutput(byte[] msg, int offset, AbstractMRMessage m) {
088        return;
089    }
090
091    /**
092     * Determine how much many bytes the entire message will take, including
093     * space for header and trailer
094     *
095     * @param m The message to be sent
096     * @return Number of bytes
097     */
098    @Override
099    protected int lengthOfByteStream(AbstractMRMessage m) {
100        return m.getNumDataElements();
101    }
102
103    // New message for hardware protocol
104    @Override
105    protected AbstractMRMessage newMessage() {
106        log.debug("New Message created");
107        Message msg = new Message();
108        return msg;
109    }
110
111    /**
112     * Make a CanReply from a system-specific reply
113     */
114    @Override
115    public CanReply decodeFromHardware(AbstractMRReply m) {
116        log.debug("Decoding from hardware: {}", m );
117        CanReply ret = new CanReply();
118        try {
119            Reply gc = (Reply) m;
120            ret = gc.createReply();
121            log.debug("Decoded {} as {} ",gc,ret);
122        } catch (java.lang.ClassCastException cce){
123                log.error("Unable to cast Reply {}",m);
124        }
125        return ret;
126    }
127
128    /**
129     * Encode a CanMessage for the hardware
130     */
131    @Override
132    public AbstractMRMessage encodeForHardware(CanMessage m) {
133        Message ret = new Message(m);
134        log.debug("Encoding for hardware as {}",ret);
135        return ret;
136    }
137
138    // New reply from hardware
139    @Override
140    protected AbstractMRReply newReply() {
141        log.debug("New Reply created");
142        Reply reply = new Reply();
143        return reply;
144    }
145
146    /*
147     * Normal Lawicall replies will end with CR; errors are BELL
148     */
149    @Override
150    protected boolean endOfMessage(AbstractMRReply r) {
151        if (endNormalReply(r)) {
152            return true;
153        }
154        return false;
155    }
156
157    boolean endNormalReply(AbstractMRReply r) {
158        // Detect if the reply buffer ends with bell or cr
159        int num = r.getNumDataElements() - 1;
160        if (r.getElement(num) == 0x0D) {
161            return true;
162        }
163        if (r.getElement(num) == 0x07) {
164            return true;
165        }
166        return false;
167    }
168
169    private int gcState;
170
171    private final static Logger log = LoggerFactory.getLogger(LawicellTrafficController.class);
172}