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     * @deprecated 5.13.5, unused, requires further development.
044     * @param a Array of bytes to send
045     */
046    @Deprecated( since="5.13.5", forRemoval=true)
047    public SerialMessage(byte[] a) {
048        // super(String.valueOf(a)); // Spotbug toString on array
049        // requires further development to produce correct values for hardware type.
050        super(StringUtil.hexStringFromBytes(a).replaceAll("\\s", ""));
051    }
052
053    @Override
054    public String toString() {
055        StringBuilder s = new StringBuilder("");
056        for (int i = 0; i < getNumDataElements(); i++) {
057            if (i != 0) {
058                s.append(" ");
059            }
060            s.append(StringUtil.twoHexFromInt(getElement(i)));
061        }
062        return s.toString();
063    }
064
065    // control when reply is expected
066    private boolean _replyExpected = true;
067
068    protected void setNoReply() {
069        _replyExpected = false;
070    }
071
072    @Override
073    public boolean replyExpected() {
074        return _replyExpected;
075    }
076
077    // static methods to recognize a message
078    public boolean isPoll() {
079        return getElement(3) == 'R' && getElement(4) == 'C';
080    }
081
082    public boolean isXmt() {
083        return getElement(3) == 'W' && getElement(4) == 'C';
084    }
085
086    public boolean isInit() {
087        return (false);
088    }  // initialization is not used in Maple
089
090    public int getUA() {
091        return ((getElement(1) - '0') * 10) + (getElement(2) - '0');
092    }
093
094    public int getAddress() {
095        return (((getElement(5) - '0') * 1000) + ((getElement(6) - '0') * 100) + ((getElement(7) - '0') * 10) + (getElement(8) - '0'));
096    }
097
098    public int getNumItems() {
099        return ((getElement(9) - '0') * 10) + (getElement(10) - '0');
100    }
101
102    // static methods to return a formatted message
103
104    static public SerialMessage getPoll(int UA, int startAdd, int count) {
105        if ((count <= 0) || (count > 99)) {
106            log.error("Illegal count in Maple poll message - {}", count);
107            return null;
108        }
109        SerialMessage m = new SerialMessage(14);
110        m.setElement(0, 02);
111        m.setElement(1, '0' + (UA / 10));
112        m.setElement(2, '0' + (UA - ((UA / 10) * 10)));
113        m.setElement(3, 'R');
114        m.setElement(4, 'C');
115        m.setElement(5, '0' + (startAdd / 1000));    // read starting at 0001
116        m.setElement(6, '0' + ((startAdd - ((startAdd / 1000) * 1000)) / 100));
117        m.setElement(7, '0' + ((startAdd - ((startAdd / 100) * 100)) / 10));
118        m.setElement(8, '0' + (startAdd - ((startAdd / 10) * 10)));
119        m.setElement(9, '0' + (count / 10));
120        m.setElement(10, '0' + (count - ((count / 10) * 10)));
121        m.setElement(11, 03);
122
123        m.setChecksum(12);
124
125        m.setTimeout(InputBits.getTimeoutTime());
126        return m;
127    }
128
129    void setChecksum(int index) {
130        int sum = 0;
131        for (int i = 1; i < index; i++) {
132            sum += getElement(i);
133        }
134        sum = sum & 0xFF;
135
136        char firstChar;
137        int firstVal = (sum / 16) & 0xF;
138        if (firstVal > 9) {
139            firstChar = (char) ('A' - 10 + firstVal);
140        } else {
141            firstChar = (char) ('0' + firstVal);
142        }
143        setElement(index, firstChar);
144
145        char secondChar;
146        int secondVal = sum & 0xf;
147        if (secondVal > 9) {
148            secondChar = (char) ('A' - 10 + secondVal);
149        } else {
150            secondChar = (char) ('0' + secondVal);
151        }
152        setElement(index + 1, secondChar);
153    }
154
155//    public int maxSize() {
156//        return DEFAULTMAXSIZE;
157//    }
158//    static public final int DEFAULTMAXSIZE = 404; // Maple RR Request Docs page 9
159
160    private final static Logger log = LoggerFactory.getLogger(SerialMessage.class);
161
162}