001package jmri.jmrix.can.adapters.lawicell;
002
003import jmri.jmrix.AbstractMRReply;
004import jmri.jmrix.can.CanReply;
005import org.slf4j.Logger;
006import org.slf4j.LoggerFactory;
007
008/**
009 * Class for replies in a LAWICELL message/reply protocol.
010 * <p>
011 *
012 * @author Andrew Crosland Copyright (C) 2008
013 * @author Bob Jacobsen Copyright (C) 2008
014 */
015public class Reply extends AbstractMRReply {
016
017    // Creates a new instance of ConnectReply
018    public Reply() {
019        super();
020    }
021
022    /*     // copy one */
023    /*     public  Reply(Reply m) { */
024    /*         super(m); */
025    /*     } */
026    public Reply(String s) {
027        _nDataChars = s.length();
028        for (int i = 0; i < s.length(); i++) {
029            _dataChars[i] = s.charAt(i);
030        }
031    }
032
033    public CanReply createReply() {
034        // is this just an ACK to e.g. a send?
035        if (_dataChars[0] != 't' && _dataChars[0] != 'T') {
036            if (log.isDebugEnabled()) {
037                log.debug("non-frame reply skipped: {}", this);
038            }
039            return null;
040        }
041        // carries a frame
042        CanReply ret = new CanReply();
043
044        ret.setExtended(isExtended());
045
046        // Copy the header
047        ret.setHeader(getHeader());
048
049        // Get the data
050        for (int i = 0; i < getNumBytes(); i++) {
051            ret.setElement(i, getByte(i));
052        }
053        ret.setNumDataElements(getNumBytes());
054        return ret;
055    }
056
057    @Override
058    protected int skipPrefix(int index) {
059        while (_dataChars[index] == ':') {
060            index++;
061        }
062        return index;
063    }
064
065    public void setData(int[] d) {
066        int len = (d.length <= 24) ? d.length : 24;
067        for (int i = 0; i < len; i++) {
068            _dataChars[i] = d[i];
069        }
070    }
071
072    public boolean isExtended() {
073        return _dataChars[0] == 'T';
074    }
075
076    /**
077     * Get the CAN header as an int
078     *
079     * @return int the CAN ID
080     */
081    public int getHeader() {
082        if (isExtended()) {
083            // 11 bit header
084            int val = 0;
085            for (int i = 1; i <= 8; i++) {
086                val = val * 16 + getHexDigit(i);
087            }
088            return val;
089        } else {
090            // 11 bit header
091            return getHexDigit(1) * 256
092                    + getHexDigit(2) * 16 + getHexDigit(3);
093        }
094    }
095
096    /**
097     * Get the number of data bytes
098     *
099     * @return int the number of bytes
100     */
101    public int getNumBytes() {
102        if (isExtended()) {
103            return _dataChars[9] - '0';
104        } else {
105            return _dataChars[4] - '0';
106        }
107    }
108
109    /**
110     * Get a hex data byte from the message
111     * <p>
112     * Data bytes are encoded as two ASCII hex digits. The starting position is
113     * byte 10 or byte 5, depending on whether this is an extended or standard
114     * message
115     *
116     * @param b The byte offset (0 - 7)
117     * @return The value
118     */
119    public int getByte(int b) {
120        if ((b >= 0) && (b <= 7)) {
121            int index = b * 2 + (isExtended() ? 10 : 5);
122            int hi = getHexDigit(index++);
123            int lo = getHexDigit(index);
124            if ((hi < 16) && (lo < 16)) {
125                return (hi * 16 + lo);
126            }
127        }
128        return 0;
129    }
130
131    // Get a single hex digit. returns 0 if digit is invalid
132    private int getHexDigit(int index) {
133        int b = 0;
134        b = _dataChars[index];
135        if ((b >= '0') && (b <= '9')) {
136            b = b - '0';
137        } else if ((b >= 'A') && (b <= 'F')) {
138            b = b - 'A' + 10;
139        } else if ((b >= 'a') && (b <= 'f')) {
140            b = b - 'a' + 10;
141        } else {
142            b = 0;
143        }
144        return (byte) b;
145    }
146
147    private final static Logger log = LoggerFactory.getLogger(Reply.class);
148}
149
150