001package jmri.jmrix.can.adapters.lawicell;
002
003import jmri.jmrix.AbstractMRMessage;
004import jmri.jmrix.can.CanMessage;
005import org.slf4j.Logger;
006import org.slf4j.LoggerFactory;
007
008/**
009 * Class for messages for a LAWICELL CAN hardware adapter.
010 * <p>
011 * The Lawicell adapter protocol encodes messages as an ASCII string of up to 24
012 * characters of the form: tiiildd...[CR] Tiiiiiiiildd...[CR] The t or T
013 * indicates a standard or extended CAN frame iiiiiiii is the header as hex
014 * digits l is the number of bytes of data dd are the (up to) 8 data bytes
015 * <p>
016 *
017 * @author Andrew Crosland Copyright (C) 2008
018 * @author Bob Jacobsen Copyright (C) 2008, 2009
019 */
020public class Message extends AbstractMRMessage {
021
022    static final int MAXLEN = 27;
023
024    public Message() {
025        _nDataChars = MAXLEN;
026        _dataChars = new int[_nDataChars];
027    }
028
029    public Message(CanMessage m) {
030        this();
031
032        // Standard or extended frame?
033        setExtended(m.isExtended());
034
035        // CAN header
036        int index = 1;
037        index = setHeader(m.getHeader(), index);
038
039        // don't know how to assert RTR in this protocol
040        if (m.isRtr()) {
041            log.error("Lawicell protocol cannot assert RTR");
042        }
043
044        // length
045        setHexDigit(m.getNumDataElements(), index++);
046
047        // Data payload
048        for (int i = 0; i < m.getNumDataElements(); i++) {
049            setHexDigit((m.getElement(i) >> 4) & 0x0F, index++);
050            setHexDigit(m.getElement(i) & 0x0F, index++);
051        }
052        // Terminator
053        setElement(index++, 0x0D);
054        setNumDataElements(index);
055    }
056
057    // accessors to the bulk data
058    @Override
059    public int getNumDataElements() {
060        return _nDataChars;
061    }
062
063    public void setNumDataElements(int n) {
064        _nDataChars = (n <= MAXLEN) ? n : MAXLEN;
065    }
066
067    @Override
068    public int getElement(int n) {
069        return _dataChars[n];
070    }
071
072    @Override
073    public void setElement(int n, int v) {
074        _dataChars[n] = v;
075    }
076
077    public void setData(int[] d) {
078        int len = (d.length <= MAXLEN) ? d.length : MAXLEN;
079        for (int i = 0; i < len; i++) {
080            _dataChars[i] = d[i];
081        }
082    }
083
084    public void setExtended(boolean extended) {
085        if (extended) {
086            // extended
087            setElement(0, 'T');
088        } else {
089            // standard
090            setElement(0, 't');
091        }
092    }
093
094    public boolean isExtended() {
095        return getElement(0) == 'T';
096    }
097
098    /**
099     * Set the CAN header as ASCII hex digits.
100     * Handles extended/standard internally.
101     *
102     * @param header A valid CAN header value
103     * @param index start index.
104     * @return index to next bytes, after this
105     */
106    public int setHeader(int header, int index) {
107        if (isExtended()) {
108            // extended MSB part
109            setHexDigit((header >> 28) & 0xF, index++);
110            setHexDigit((header >> 24) & 0xF, index++);
111            setHexDigit((header >> 20) & 0xF, index++);
112            setHexDigit((header >> 16) & 0xF, index++);
113            setHexDigit((header >> 12) & 0xF, index++);
114        }
115        // standard part
116        setHexDigit((header >> 8) & 0xF, index++);
117        setHexDigit((header >> 4) & 0xF, index++);
118        setHexDigit((header >> 0) & 0xF, index++);
119
120        return index;
121    }
122
123    /**
124     * Set a byte as two ASCII hex digits
125     * <p>
126     * Data bytes are encoded as two ASCII hex digits starting at byte 7 of the
127     * message.
128     *
129     * @param val the value to set
130     * @param n   the index of the byte to be set
131     */
132    public void setByte(int val, int n) {
133        if ((n >= 0) && (n <= 7)) {
134            int index = n * 2 + 7;
135            setHexDigit((val / 16) & 0xF, index++);
136            setHexDigit(val & 0xF, index);
137        }
138    }
139
140    // Set a hex digit at offset n in _dataChars
141    void setHexDigit(int val, int n) {
142        if ((val >= 0) && (val <= 15)) {
143            if (val < 10) {
144                _dataChars[n] = val + '0';
145            } else {
146                _dataChars[n] = val - 10 + 'A';
147            }
148        } else {
149            _dataChars[n] = '0';
150        }
151    }
152
153    private final static Logger log = LoggerFactory.getLogger(Message.class);
154}
155
156