001package jmri.jmrix.can;
002
003import javax.annotation.Nonnull;
004import jmri.jmrix.AbstractMRReply;
005
006/**
007 * Base class for replies in a CANbus based message/reply protocol.
008 * <p>
009 * It is expected that any CAN based system will be based upon basic CANbus
010 * concepts such as ID (standard or extended), Normal and RTR frames and a data
011 * field.
012 * <p>
013 * "header" refers to the full 11 or 29 bit header; which mode is separately set
014 * via the "extended" parameter
015 * <p>
016 * CBUS uses a 2-bit "Pri" field and 7-bit "ID" ("CAN ID") field, with separate
017 * accessors.
018 *
019 * @author Andrew Crosland Copyright (C) 2008
020 * @author Bob Jacobsen Copyright (C) 2008, 2009, 2010
021 */
022public class CanReply extends AbstractMRReply implements CanMutableFrame {
023
024    /**
025     * Create a new CanReply
026     */
027    public CanReply() {
028        _isExtended = false;
029        _isRtr = false;
030        _nDataChars = 8;
031        super.setBinary(true);
032        _dataChars = new int[8];
033    }
034
035    /**
036     * Create a new CanReply of given data length
037     * @param i number of data bytes, 0-8
038     */
039    public CanReply(int i) {
040        this();
041        setNumDataElements((i <= 8) ? i : 8);
042    }
043
044    /**
045     * Create a new CanReply from an int array
046     * @param d array of CAN Frame data bytes, max 8
047     */
048    public CanReply(int[] d) {
049        this();
050        setData(d);
051        setNumDataElements((d.length <= 8) ? d.length : 8);
052    }
053    
054    /**
055     * Create a new CanReply from an int array, with header
056     * @param d array of CAN Frame data bytes, max 8
057     * @param header the Frame header value
058     */
059    public CanReply(int[] d, int header) {
060        this();
061        setHeader(header);
062        setData(d);
063        setNumDataElements((d.length <= 8) ? d.length : 8);
064    }
065
066    /**
067     * Create a new CanReply from an existing CanReply
068     * @param m The existing CanReply
069     */
070    public CanReply(@Nonnull CanReply m) {
071        this();
072        _header = m.getHeader();
073        _isExtended = m.isExtended();
074        _isRtr = m.isRtr();
075        super.setBinary(true);
076        setData(m.getData());
077        setNumDataElements(m.getNumDataElements());
078    }
079
080    /**
081     * Create a new CanReply from an existing CanMessage
082     * @param m The existing CanMessage
083     */
084    public CanReply(@Nonnull CanMessage m) {
085        this();
086        _header = m.getHeader();
087        _isExtended = m.isExtended();
088        _isRtr = m.isRtr();
089        super.setBinary(true);
090        setData(java.util.Arrays.copyOf(m.getData(),m.getNumDataElements()));
091        setNumDataElements(m.getNumDataElements());
092    }
093
094    /**
095     * Hash on the header
096     */
097    @Override
098    public int hashCode() {
099        return _header;
100    }
101
102    /**
103     * Note that a CanMessage and a CanReply can be tested for equality
104     */
105    @Override
106    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "EQ_UNUSUAL",
107        justification = "Equality test done in CanFrame")
108    public boolean equals(Object a) {
109        return isEqual(a,this);
110    }
111    
112    /**
113     * {@inheritDoc}
114     */
115    @Override
116    protected int skipPrefix(int index) {
117        return index;
118    }
119
120    /**
121     * {@inheritDoc}
122     */
123    @Override
124    public int getNumDataElements() {
125        return _nDataChars;
126    }
127
128    /**
129     * {@inheritDoc}
130     */
131    @Override
132    public final void setNumDataElements(int n) {
133        _nDataChars = (n <= 8) ? n : 8;
134    }
135
136    /**
137     * {@inheritDoc}
138     */
139    @Override
140    public int getElement(int n) {
141        return _dataChars[n];
142    }
143
144    /**
145     * {@inheritDoc}
146     */
147    @Override
148    public void setElement(int n, int v) {
149        _dataChars[n] = v;
150    }
151
152    /**
153     * Get the data byte array.
154     * @return the actual byte array, not a Copy Of
155     */
156    public int[] getData() {
157        return _dataChars;
158    }
159
160    /**
161     * {@inheritDoc}
162     */
163    @Override
164    public int getHeader() {
165        return _header;
166    }
167
168    /**
169     * {@inheritDoc}
170     */
171    @Override
172    public final void setHeader(int h) {
173        _header = h;
174    }
175
176    /**
177     * {@inheritDoc}
178     */
179    @Override
180    public boolean isExtended() {
181        return _isExtended;
182    }
183
184    /**
185     * {@inheritDoc}
186     */
187    @Override
188    public void setExtended(boolean b) {
189        _isExtended = b;
190    }
191
192    /**
193     * {@inheritDoc}
194     */
195    @Override
196    public boolean isRtr() {
197        return _isRtr;
198    }
199
200    /**
201     * {@inheritDoc}
202     */
203    @Override
204    public void setRtr(boolean b) {
205        _isRtr = b;
206    }
207
208    /**
209     * {@inheritDoc}
210     * this format matches @CanMessage
211     */
212    @Override
213    public String toString() {
214        return getToString();
215    }
216
217    /**
218     * {@inheritDoc}
219     * this format matches @CanMessage
220     */
221    @Override
222    public String toMonitorString() {
223        return monString();
224    }
225
226    // contents (package access)
227    int _header;
228    boolean _isExtended;
229    boolean _isRtr;
230}