001package jmri.jmrix.ieee802154;
002
003/**
004 * Contains the data payload of a serial reply packet. Note that it's _only_ the
005 * payload.
006 *
007 * @author Bob Jacobsen Copyright (C) 2002, 2006, 2007, 2008 Converted to
008 * multiple connection
009 * @author kcameron Copyright (C) 2011 Modified for IEEE 802.15.4 connection
010 * @author Paul Bender Copyright (C) 2013
011 */
012public class IEEE802154Reply extends jmri.jmrix.AbstractMRReply {
013
014    // create a new one
015    public IEEE802154Reply() {
016        super();
017        setBinary(true);
018    }
019
020    public IEEE802154Reply(String s) {
021        super(s);
022        setBinary(true);
023    }
024
025    public IEEE802154Reply(IEEE802154Reply l) {
026        super(l);
027        setBinary(true);
028    }
029
030    /*
031     * @return the destination address associated with the reply (need for 
032     * matching to a node ).  The type and position of the sender 
033     * address is indicated in the control byte.
034     */
035    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS",
036        justification = "Would take significant rework")
037    public byte[] getDestinationAddress() {
038        int destinationMode = getDestinationAddressMode();
039        //int sourceMode = getSourceAddressMode(); // not used
040        int offset = 4; // position of first byte of destination address if
041        // it is present.
042        int length = 0; // minimum destination address length.
043        // both address may be either 0, 2, or 8 bytes, depending on
044        // the addressing mode used.  destination mode determins the
045        // source address offset.
046        switch (destinationMode) {
047            case 0x00:
048                return null;  // no destination address.
049            case 0x01:
050                return null;  // this value is reserved.
051            case 0x10:
052                length += 2; // 16 bit address
053                break;
054            case 0x11:
055                length += 8; // 64 bit address
056                break;
057            default:
058                return null; // this should never actually happen.
059        }
060
061        if (!isIntraPanFrame()) {
062            // this is an interpan frame. pan addresses
063            // are included if both address fields
064            // are present.
065            if (destinationMode != 0) {
066                offset += 2;
067            }
068        }
069
070        byte address[] = new byte[length];
071        for (int i = 0; i < length; i++) {
072            address[i] = (byte) (0xff & getElement(i + offset));
073        }
074        return address;
075    }
076
077    /*
078     * @return the sender address associated with the reply (need for 
079     * matching to a node ).  The type and position of the sender 
080     * address is indicated in the control byte.
081     */
082    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS",
083        justification = "Would take significant rework")
084    public byte[] getSourceAddr() {
085        int destinationMode = getDestinationAddressMode();
086        int sourceMode = getSourceAddressMode();
087        int offset = 4; // position of first byte of source address if
088        // no destination address is present.
089        int length = 0; // minimum source address length.
090        // both address may be either 0, 2, or 8 bytes, depending on
091        // the addressing mode used.  destination mode determins the
092        // source address offset.
093        switch (destinationMode) {
094            case 0x00:
095                break;  // no destination address.
096            case 0x01:
097                break;  // this value is reserved.
098            case 0x10:
099                offset += 2; // 16 bit address
100                break;
101            case 0x11:
102                offset += 8; // 64 bit address
103                break;
104            default:
105                return null; // this should never actually happen.
106        }
107        switch (sourceMode) {
108            case 0x00:
109                return null; // no source address.
110            case 0x01:
111                return null; // this value is reserved.
112            case 0x10:
113                length += 2; // 16 bit address
114                break;
115            case 0x11:
116                length += 8; // 64 bit address
117                break;
118            default:
119                return null; // this should never actually happen.
120        }
121
122        if (!isIntraPanFrame()) {
123            // this is an interpan frame. pan addresses
124            // are included if both address fields
125            // are present.
126            if (destinationMode != 0 && sourceMode != 0) {
127                offset += 4;
128            }
129        }
130
131        byte address[] = new byte[length];
132        for (int i = 0; i < length; i++) {
133            address[i] = (byte) (0xff & getElement(i + offset));
134        }
135        return address;
136    }
137
138    /*
139     * @return the payload associated with the reply.  The position
140     * of the data is determined from the control byte.
141     */
142    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS",
143        justification = "Would take significant rework")
144    public byte[] getPayload() {
145        int destinationMode = getDestinationAddressMode();
146        int sourceMode = getSourceAddressMode();
147        int offset = 4; // position of first byte of source address if
148        // no destination address is present.
149        // both address may be either 0, 2, or 8 bytes, depending on
150        // the addressing mode used.  destination mode determins the
151        // source address offset.
152        switch (destinationMode) {
153            case 0x00:
154                break;  // no destination address.
155            case 0x01:
156                break;  // this value is reserved.
157            case 0x10:
158                offset += 2; // 16 bit address
159                break;
160            case 0x11:
161                offset += 8; // 64 bit address
162                break;
163            default:
164                return null; // this should never actually happen.
165        }
166        switch (sourceMode) {
167            case 0x00:
168                break; // no source address.
169            case 0x01:
170                break; // this value is reserved.
171            case 0x10:
172                offset += 2; // 16 bit address
173                break;
174            case 0x11:
175                offset += 8; // 64 bit address
176                break;
177            default:
178                return null; // this should never actually happen.
179        }
180
181        if (!isIntraPanFrame()) {
182            // this is an interpan frame. pan addresses
183            // are included if both address fields
184            // are present.
185            if (destinationMode != 0 && sourceMode != 0) {
186                offset += 4;
187            }
188        }
189
190        int length = getLength() - (offset + 2); // the payload starts after
191        // the address and ends
192        // at the 2 byte checksum.
193
194        byte address[] = new byte[length];
195        for (int i = 0; i < length; i++) {
196            address[i] = (byte) (0xff & getElement(i + offset));
197        }
198        return address;
199    }
200
201    /*
202     * @return length of reply.  length is the first byte after
203     * the start byte.  We are not storing the start byte.
204     * <p>
205     * NOTE: this does not work correctly for packets received from
206     * an XBee Node.  These devices do not provide raw packet 
207     * information.
208     */
209    public int getLength() {
210        return getElement(0);
211    }
212
213    /*
214     * @return control information from the reply.  This is the 3rd and 4th 
215     * byte after the start byte.
216     * Format of the frame control field (FCF)
217     *  according to IEEE 802.15.4 MAC standard
218     *
219     * bits 0-2   frame type
220     *      3     security enabled
221     *      4     frame pending
222     *      5     acknowledge request
223     *      6     intra pan
224     *      7-9   reserved
225     *      10-11 destination addressing mode
226     *      12-13 reserved
227     *      14-15 source addressing mode
228     * 
229     */
230    public int getFrameControl() {
231        return (getElement(1) << 8) + getElement(2);
232    }
233
234    // return the destination address mode (bits 10 and 11) of the frame
235    // control field.
236    public int getDestinationAddressMode() {
237        return ((getFrameControl() & 0x0C00) >> 10);
238    }
239
240    // return the source address mode (bits 14 and 15) of the frame
241    // control field.
242    public int getSourceAddressMode() {
243        return ((getFrameControl() & 0xC000) >> 14);
244    }
245
246    // return whether or not the intrapan frame bit (bit 6) is set in
247    // the frame control field.
248    public boolean isIntraPanFrame() {
249        return ((getFrameControl() & 0x0020) != 0);
250    }
251
252    /*
253     * @return the sequence number of the reply.  This is the 4th byte 
254     * after the start byte.
255     */
256    public byte getSequenceByte() {
257        return (byte) getElement(3);
258    }
259
260    @Override
261    protected int skipPrefix(int index) {
262        // doesn't have to do anything
263        return index;
264    }
265
266    /**
267     * check whether the message has a valid parity IEEE 802.15.4 messages have
268     * a two byte parity.
269     * @return true if parity valid
270     */
271    public boolean checkParity() {
272        int len = getNumDataElements();
273        int chksum = 0x0000;  /* the seed */
274
275        int loop;
276
277        for (loop = 0; loop < len - 1; loop = loop + 2) {  // calculate contents for data part
278            chksum ^= (getElement(loop) << 8);
279            chksum ^= getElement(loop + 1);
280        }
281        return ((chksum & 0xFFFF) == ((getElement(len - 2) << 8) + getElement(len - 1)));
282    }
283
284}