001package jmri.jmrix.grapevine;
002
003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
004import org.slf4j.Logger;
005import org.slf4j.LoggerFactory;
006
007/**
008 * Contains the data payload of a serial reply packet. Note that it's _only_ the
009 * payload.
010 *
011 * @author Bob Jacobsen Copyright (C) 2002, 2006, 2007, 2008
012 */
013public class SerialReply extends jmri.jmrix.AbstractMRReply {
014
015    /**
016     * Create a new SerialReply instance.
017     */
018    public SerialReply() {
019        super(); // normal Grapevine replies are four bytes, binary
020        setBinary(true);
021    }
022
023    /**
024     * Copy a Reply to a new SerialReply instance.
025     *
026     * @param l the reply to copy
027     */
028    public SerialReply(SerialReply l) {
029        super(l);
030        setBinary(true);
031    }
032
033    /**
034     * Create a new SerialReply instance from a string.
035     *
036     * @param s String to use as reply content
037     */
038    public SerialReply(String s) {
039        super(s);
040        setBinary(true);
041    }
042
043    /**
044     * Is reply to poll message.
045     * @return true if reply to a poll message, else false.
046     */
047    public int getAddr() {
048        return getElement(0) & 0x7F;
049    }
050
051    @Override
052    public boolean isUnsolicited() {
053        return true;
054    } // always unsolicited!
055
056    @Override
057    protected int skipPrefix(int index) {
058        // doesn't have to do anything
059        return index;
060    }
061
062    public int getBank() {
063        return ((getElement(3) & 0x70) >> 4);
064    }
065
066    public boolean isError() {
067        return (getElement(0) & 0x7F) == 0;
068    }
069
070    public boolean isFromParallelSensor() {
071        // bank 5?
072        if ((getElement(3) & 0x70) != 0x50) {
073            return false;
074        }
075        if ((getElement(1) & 0x20) != 0x00) {
076            return false;
077        }
078        return true;
079    }
080
081    public boolean isFromOldSerialSensor() {
082        // bank 5?
083        if ((getElement(3) & 0x70) != 0x50) {
084            return false;
085        }
086        if ((getElement(1) & 0x20) != 0x20) {
087            return false;
088        }
089        return true;
090    }
091
092    public boolean isFromNewSerialSensor() {
093        // bank 4?
094        if ((getElement(3) & 0x70) != 0x40) {
095            return false;
096        }
097        return true;
098    }
099
100    public void setNumDataElements(int len) {
101        if (len > _nDataChars) {
102            log.error("Can't shorten reply from {} to {}", _nDataChars, len);
103            return;
104        }
105        _nDataChars = len;
106    }
107
108    /**
109     * Format the reply as human-readable text.
110     * <p>
111     * Since Grapevine doesn't distinguish between message and reply, this uses
112     * the Message method.
113     * @return human readable text of reply.
114     */
115    @SuppressWarnings("fallthrough")
116    @SuppressFBWarnings(value = "SF_SWITCH_FALLTHROUGH")
117    public String format() {
118        int b1 = -1;
119        int b2 = -1;
120        int b3 = -1;
121        int b4 = -1;
122        switch (getNumDataElements()) {
123            case 4:
124                b4 = getElement(3) & 0xff;
125            // fall through
126            case 3:
127                b3 = getElement(2) & 0xff;
128            // fall through
129            case 2:
130                b2 = getElement(1) & 0xff;
131            // fall through
132            case 1:
133                b1 = getElement(0) & 0xff;
134                break;
135            default:
136                log.warn("Unhandled number of elements: {}", getNumDataElements());
137                break;
138        }
139
140        return SerialMessage.staticFormat(b1, b2, b3, b4);
141    }
142
143    private final static Logger log = LoggerFactory.getLogger(SerialReply.class);
144
145}
146
147