001package jmri.jmrix.maple;
002
003import jmri.util.StringUtil;
004import org.slf4j.Logger;
005import org.slf4j.LoggerFactory;
006
007/**
008 * Contains the data payload of a serial packet.
009 * <p>
010 * Note that <i>only</i> the payload, not the header or trailer, nor the padding
011 * DLE characters are included. These are added during transmission.
012 *
013 * @author Bob Jacobsen Copyright (C) 2001,2003
014 */
015public class SerialMessage extends jmri.jmrix.AbstractMRMessage {
016    // is this logically an abstract class?
017
018    public SerialMessage() {
019        super();
020    }
021
022    // create a new one
023    public SerialMessage(int i) {
024        super(i);
025    }
026
027    // copy one
028    public SerialMessage(SerialMessage m) {
029        super(m);
030    }
031
032    /**
033     * This ctor interprets the String as the exact sequence to send,
034     * byte-for-byte.
035     * @param m message string.
036     */
037    public SerialMessage(String m) {
038        super(m);
039    }
040
041    /**
042     * This ctor interprets the byte array as a sequence of characters to send.
043     *
044     * @param a Array of bytes to send
045     */
046    public SerialMessage(byte[] a) {
047        super(String.valueOf(a));
048    }
049
050    @Override
051    public String toString() {
052        StringBuilder s = new StringBuilder("");
053        for (int i = 0; i < getNumDataElements(); i++) {
054            if (i != 0) {
055                s.append(" ");
056            }
057            s.append(StringUtil.twoHexFromInt(getElement(i)));
058        }
059        return s.toString();
060    }
061
062    // control when reply is expected
063    private boolean _replyExpected = true;
064
065    protected void setNoReply() {
066        _replyExpected = false;
067    }
068
069    @Override
070    public boolean replyExpected() {
071        return _replyExpected;
072    }
073
074    // static methods to recognize a message
075    public boolean isPoll() {
076        return getElement(3) == 'R' && getElement(4) == 'C';
077    }
078
079    public boolean isXmt() {
080        return getElement(3) == 'W' && getElement(4) == 'C';
081    }
082
083    public boolean isInit() {
084        return (false);
085    }  // initialization is not used in Maple
086
087    public int getUA() {
088        return ((getElement(1) - '0') * 10) + (getElement(2) - '0');
089    }
090
091    public int getAddress() {
092        return (((getElement(5) - '0') * 1000) + ((getElement(6) - '0') * 100) + ((getElement(7) - '0') * 10) + (getElement(8) - '0'));
093    }
094
095    public int getNumItems() {
096        return ((getElement(9) - '0') * 10) + (getElement(10) - '0');
097    }
098
099    // static methods to return a formatted message
100
101    static public SerialMessage getPoll(int UA, int startAdd, int count) {
102        if ((count <= 0) || (count > 99)) {
103            log.error("Illegal count in Maple poll message - {}", count);
104            return null;
105        }
106        SerialMessage m = new SerialMessage(14);
107        m.setElement(0, 02);
108        m.setElement(1, '0' + (UA / 10));
109        m.setElement(2, '0' + (UA - ((UA / 10) * 10)));
110        m.setElement(3, 'R');
111        m.setElement(4, 'C');
112        m.setElement(5, '0' + (startAdd / 1000));    // read starting at 0001
113        m.setElement(6, '0' + ((startAdd - ((startAdd / 1000) * 1000)) / 100));
114        m.setElement(7, '0' + ((startAdd - ((startAdd / 100) * 100)) / 10));
115        m.setElement(8, '0' + (startAdd - ((startAdd / 10) * 10)));
116        m.setElement(9, '0' + (count / 10));
117        m.setElement(10, '0' + (count - ((count / 10) * 10)));
118        m.setElement(11, 03);
119
120        m.setChecksum(12);
121
122        m.setTimeout(InputBits.getTimeoutTime());
123        return m;
124    }
125
126    void setChecksum(int index) {
127        int sum = 0;
128        for (int i = 1; i < index; i++) {
129            sum += getElement(i);
130        }
131        sum = sum & 0xFF;
132
133        char firstChar;
134        int firstVal = (sum / 16) & 0xF;
135        if (firstVal > 9) {
136            firstChar = (char) ('A' - 10 + firstVal);
137        } else {
138            firstChar = (char) ('0' + firstVal);
139        }
140        setElement(index, firstChar);
141
142        char secondChar;
143        int secondVal = sum & 0xf;
144        if (secondVal > 9) {
145            secondChar = (char) ('A' - 10 + secondVal);
146        } else {
147            secondChar = (char) ('0' + secondVal);
148        }
149        setElement(index + 1, secondChar);
150    }
151
152//    public int maxSize() {
153//        return DEFAULTMAXSIZE;
154//    }
155//    static public final int DEFAULTMAXSIZE = 404; // Maple RR Request Docs page 9
156
157    private final static Logger log = LoggerFactory.getLogger(SerialMessage.class);
158
159}