001package jmri.jmrix.can;
002
003import javax.annotation.Nonnull;
004import jmri.jmrix.AbstractMRMessage;
005
006/**
007 * Base class for messages 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 * The _dataChars[] and _nDataChars members refer to the data field, not the
014 * entire message.
015 * <p>
016 * "header" refers to the full 11 or 29 bit header; which mode is separately set
017 * via the "extended" parameter
018 * <p>
019 * CBUS uses a 2-bit "Pri" field and 7-bit "ID" ("CAN ID") field, with separate
020 * accessors. CBUS ID is set as a layout connection preference and registered by
021 * the traffic controller.
022 *
023 * @author Andrew Crosland Copyright (C) 2008
024 * @author Bob Jacobsen Copyright (C) 2008, 2009, 2010
025 */
026public class CanMessage extends AbstractMRMessage implements CanMutableFrame {
027    
028    private boolean _translated = false;
029
030    /**
031     * Create a new CanMessage with 8 data bytes
032     * @param header The CAN Frame header value
033     */
034    public CanMessage(int header) {
035        _header = header;
036        _isExtended = false;
037        _isRtr = false;
038        _nDataChars = 8;
039        super.setBinary(true);
040        _dataChars = new int[8];
041    }
042    
043    /**
044     * Create a new CanMessage of given length
045     * @param numDataBytes number of CAN Frame data bytes, max 8
046     * @param header The CAN Frame header value
047     */
048    public CanMessage(int numDataBytes, int header) {
049        this(header);
050        _nDataChars = (numDataBytes <= 8) ? numDataBytes : 8;
051    }
052    
053    /**
054     * Create a new CanMessage from an int array
055     * @param d array of CAN Frame data bytes, max 8
056     * @param header The CAN Frame header value
057     */
058    public CanMessage(int[] d, int header) {
059        this(header);
060        setData(d);
061        setNumDataElements((d.length <= 8) ? d.length : 8);
062    }
063
064    /**
065     * Create a new CanMessage from a byte array
066     * @param d array of CAN Frame data bytes, max 8
067     * @param header The CAN Frame header value
068     */
069    public CanMessage(byte[] d, int header) {
070        this(header);
071        setData(d);
072        setNumDataElements((d.length <= 8) ? d.length : 8);
073    }
074
075    /**
076     * Create a new CanMessage from an existing CanMessage
077     * @param m The existing CanMessage
078     */
079    public CanMessage(@Nonnull CanMessage m) {
080        this(m.getHeader());
081        _isExtended = m.isExtended();
082        _isRtr = m.isRtr();
083        super.setBinary(true);
084        setData(java.util.Arrays.copyOf(m.getData(),m.getNumDataElements()));
085        setNumDataElements(m.getNumDataElements());
086    }
087
088    /**
089     * Create a new CanMessage from an existing CanReply
090     * @param m The existing CanReply
091     */
092    public CanMessage(@Nonnull CanReply m) {
093        this(m.getHeader());
094        _isExtended = m.isExtended();
095        _isRtr = m.isRtr();
096        super.setBinary(true);
097        setData(m.getData());
098        setNumDataElements(m.getNumDataElements());
099    }
100    
101    /**
102     * Tag whether translation is needed.
103     * a "native" message has been converted already.
104     * @param translated true or false to set flag as required
105     */
106    public void setTranslated(boolean translated) {
107        _translated = translated;
108    }
109    
110    /**
111     * Check if translation flag has been set.
112     * @return false by default
113     */
114    public boolean isTranslated() {
115        return _translated;
116    }
117
118    /**
119     * Hash on the header
120     */
121    @Override
122    public int hashCode() {
123        return _header;
124    }
125
126    /**
127     * Note that a CanMessage and a CanReply can be tested for equality.
128     * @param a CanMessage or CanReply to test against
129     */
130    @Override
131    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "EQ_UNUSUAL",
132        justification = "Equality test done in CanFrame")
133    public boolean equals(Object a) {
134        return isEqual(this,a);
135    }
136
137    /**
138     * {@inheritDoc}
139     * This format matches {@link CanReply}
140     */
141    @Override
142    public String toString() {
143        return getToString();
144    }
145
146    /**
147     * {@inheritDoc}
148     * This format matches {@link CanReply}
149     */
150    @Override
151    public String toMonitorString() {
152        return monString();
153    }
154
155    /**
156     * {@inheritDoc}
157     * @return always false
158     */
159    @Override
160    public boolean replyExpected() {
161        return false;
162    }
163    
164    /**
165     * {@inheritDoc}
166     */
167    @Override
168    public int getNumDataElements() {
169        return _nDataChars;
170    }
171
172    /**
173     * {@inheritDoc}
174     */
175    @Override
176    public final void setNumDataElements(int n) {
177        _nDataChars = n;
178    }
179
180    /**
181     * {@inheritDoc}
182     */
183    @Override
184    public int getElement(int n) {
185        return _dataChars[n];
186    }
187
188    /**
189     * {@inheritDoc}
190     */
191    @Override
192    public void setElement(int n, int v) {
193        _dataChars[n] = v;
194    }
195
196    /**
197     * Get the data bytes in array form.
198     * @return the actual int array
199     */
200    public int[] getData() {
201        return _dataChars;
202    }
203
204    /**
205     * {@inheritDoc}
206     */
207    @Override
208    public int getHeader() {
209        return _header;
210    }
211
212    /**
213     * {@inheritDoc}
214     */
215    @Override
216    public void setHeader(int h) {
217        _header = h;
218    }
219
220    /**
221     * {@inheritDoc}
222     */
223    @Override
224    public boolean isExtended() {
225        return _isExtended;
226    }
227
228    /**
229     * {@inheritDoc}
230     */
231    @Override
232    public void setExtended(boolean b) {
233        _isExtended = b;
234    }
235
236    /**
237     * {@inheritDoc}
238     */
239    @Override
240    public boolean isRtr() {
241        return _isRtr;
242    }
243
244    /**
245     * {@inheritDoc}
246     */
247    @Override
248    public void setRtr(boolean b) {
249        _isRtr = b;
250    }
251
252    // contents (package access)
253    int _header;
254    boolean _isExtended;
255    boolean _isRtr;
256}