    001/**
    002 * Copyright (c) 2014 Digi International Inc.,
    003 * All rights not expressly granted are reserved.
    004 *
    005 * This Source Code Form is subject to the terms of the Mozilla Public
    006 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
    007 * You can obtain one at http://mozilla.org/MPL/2.0/.
    008 *
    009 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
    010 * =======================================================================
    011 */
    012package com.digi.xbee.api.packet.common;
    013
    014import java.io.ByteArrayOutputStream;
    015import java.io.IOException;
    016import java.util.Arrays;
    017import java.util.LinkedHashMap;
    018
    019import org.slf4j.Logger;
    020import org.slf4j.LoggerFactory;
    021
    022import com.digi.xbee.api.models.XBee16BitAddress;
    023import com.digi.xbee.api.models.XBee64BitAddress;
    024import com.digi.xbee.api.packet.XBeeAPIPacket;
    025import com.digi.xbee.api.packet.APIFrameType;
    026import com.digi.xbee.api.utils.ByteUtils;
    027import com.digi.xbee.api.utils.HexUtils;
    028
    029/**
    030 * This class represents a Receive Packet. Packet is built using the parameters
    031 * of the constructor or providing a valid API payload.
    032 *
    033 * <p>When the module receives an RF packet, it is sent out the UART using this
    034 * message type.</p>
    035 *
    036 * <p>This packet is received when external devices send transmit request
    037 * packets to this module.</p>
    038 *
    039 * <p>Among received data, some options can also be received indicating
    040 * transmission parameters.</p>
    041 *
    042 * @see TransmitPacket
    043 * @see com.digi.xbee.api.models.XBeeReceiveOptions
    044 * @see com.digi.xbee.api.packet.XBeeAPIPacket
    045 */
    046public class ReceivePacket extends XBeeAPIPacket {
    047
    048        // Constants.
    049        private static final int MIN_API_PAYLOAD_LENGTH = 12; // 1 (Frame type) + 8 (32-bit address) + 2 (16-bit address) + 1 (receive options)
    050
    051        // Variables.
    052        private final XBee64BitAddress sourceAddress64;
    053
    054        private final XBee16BitAddress sourceAddress16;
    055
    056        private final int receiveOptions;
    057
    058        private byte[] rfData;
    059
    060        private Logger logger;
    061
    062        /**
    063         * Creates a new {@code ReceivePacket} object from the given payload.
    064         *
    065         * @param payload The API frame payload. It must start with the frame type
    066         *                corresponding to a Receive packet ({@code 0x90}).
    067         *                The byte array must be in {@code OperatingMode.API} mode.
    068         *
    069         * @return Parsed ZigBee Receive packet.
    070         *
    071         * @throws IllegalArgumentException if {@code payload[0] != APIFrameType.RECEIVE_PACKET.getValue()} or
    072         *                                  if {@code payload.length < {@value #MIN_API_PAYLOAD_LENGTH}} or
    073         *                                  if {@code receiveOptions < 0} or
    074         *                                  if {@code receiveOptions > 255}.
    075         * @throws NullPointerException if {@code payload == null}.
    076         */
    077        public static ReceivePacket createPacket(byte[] payload) {
    078                if (payload == null)
    079                        throw new NullPointerException("Receive packet payload cannot be null.");
    080
    081                // 1 (Frame type) + 8 (32-bit address) + 2 (16-bit address) + 1 (receive options)
    082                if (payload.length < MIN_API_PAYLOAD_LENGTH)
    083                        throw new IllegalArgumentException("Incomplete Receive packet.");
    084
    085                if ((payload[0] & 0xFF) != APIFrameType.RECEIVE_PACKET.getValue())
    086                        throw new IllegalArgumentException("Payload is not a Receive packet.");
    087
    088                // payload[0] is the frame type.
    089                int index = 1;
    090
    091                // 2 bytes of 16-bit address.
    092                XBee64BitAddress sourceAddress64 = new XBee64BitAddress(Arrays.copyOfRange(payload, index, index + 8));
    093                index = index + 8;
    094
    095                // 2 bytes of 16-bit address.
    096                XBee16BitAddress sourceAddress16 = new XBee16BitAddress(payload[index] & 0xFF, payload[index + 1] & 0xFF);
    097                index = index + 2;
    098
    099                // Receive options
    100                int receiveOptions = payload[index] & 0xFF;
    101                index = index + 1;
    102
    103                // Get data.
    104                byte[] data = null;
    105                if (index < payload.length)
    106                        data = Arrays.copyOfRange(payload, index, payload.length);
    107
    108                return new ReceivePacket(sourceAddress64, sourceAddress16, receiveOptions, data);
    109        }
    110
    111        /**
    112         * Class constructor. Instantiates a new {@code ReceivePacket} object
    113         * with the given parameters.
    114         *
    115         * @param sourceAddress64 64-bit address of the sender.
    116         * @param sourceAddress16 16-bit address of the sender.
    117         * @param receiveOptions Bitfield indicating the receive options.
    118         * @param rfData Received RF data.
    119         *
    120         * @throws IllegalArgumentException if {@code receiveOptions < 0} or
    121         *                                  if {@code receiveOptions > 255}.
    122         * @throws NullPointerException if {@code sourceAddress64 == null} or
    123         *                              if {@code sourceAddress16 == null}.
    124         *
    125         * @see com.digi.xbee.api.models.XBeeReceiveOptions
    126         * @see com.digi.xbee.api.models.XBee16BitAddress
    127         * @see com.digi.xbee.api.models.XBee64BitAddress
    128         */
    129        public ReceivePacket(XBee64BitAddress sourceAddress64, XBee16BitAddress sourceAddress16, int receiveOptions, byte[] rfData){
    130                super(APIFrameType.RECEIVE_PACKET);
    131
    132                if (sourceAddress64 == null)
    133                        throw new NullPointerException("64-bit source address cannot be null.");
    134                if (sourceAddress16 == null)
    135                        throw new NullPointerException("16-bit source address cannot be null.");
    136                if (receiveOptions < 0 || receiveOptions > 255)
    137                        throw new IllegalArgumentException("Receive options value must be between 0 and 255.");
    138
    139                this.sourceAddress64 = sourceAddress64;
    140                this.sourceAddress16 = sourceAddress16;
    141                this.receiveOptions = receiveOptions;
    142                this.rfData = rfData;
    143                this.logger = LoggerFactory.getLogger(ReceivePacket.class);
    144        }
    145
    146        /*
    147         * (non-Javadoc)
    148         * @see com.digi.xbee.api.packet.XBeeAPIPacket#getAPIPacketSpecificData()
    149         */
    150        @Override
    151        protected byte[] getAPIPacketSpecificData() {
    152                ByteArrayOutputStream data = new ByteArrayOutputStream();
    153                try {
    154                        data.write(sourceAddress64.getValue());
    155                        data.write(sourceAddress16.getValue());
    156                        data.write(receiveOptions);
    157                        if (rfData != null)
    158                                data.write(rfData);
    159                } catch (IOException e) {
    160                        logger.error(e.getMessage(), e);
    161                }
    162                return data.toByteArray();
    163        }
    164
    165        /*
    166         * (non-Javadoc)
    167         * @see com.digi.xbee.api.packet.XBeeAPIPacket#needsAPIFrameID()
    168         */
    169        @Override
    170        public boolean needsAPIFrameID() {
    171                return false;
    172        }
    173
    174        /*
    175         * (non-Javadoc)
    176         * @see com.digi.xbee.api.packet.XBeeAPIPacket#isBroadcast()
    177         */
    178        @Override
    179        public boolean isBroadcast() {
    180                if (ByteUtils.isBitEnabled(getReceiveOptions(), 1))
    181                        return true;
    182                return false;
    183        }
    184
    185        /**
    186         * Returns the 64-bit sender/source address.
    187         *
    188         * @return The 64-bit sender/source address.
    189         *
    190         * @see com.digi.xbee.api.models.XBee64BitAddress
    191         */
    192        public XBee64BitAddress get64bitSourceAddress() {
    193                return sourceAddress64;
    194        }
    195
    196        /**
    197         * Returns the 16-bit sender/source address.
    198         *
    199         * @return The 16-bit sender/source address.
    200         *
    201         * @see com.digi.xbee.api.models.XBee16BitAddress
    202         */
    203        public XBee16BitAddress get16bitSourceAddress() {
    204                return sourceAddress16;
    205        }
    206
    207        /**
    208         * Returns the receive options bitfield.
    209         *
    210         * @return Receive options bitfield.
    211         *
    212         * @see com.digi.xbee.api.models.XBeeReceiveOptions
    213         */
    214        public int getReceiveOptions() {
    215                return receiveOptions;
    216        }
    217
    218        /**
    219         * Sets the received RF data.
    220         *
    221         * @param rfData Received RF data.
    222         */
    223        public void setRFData(byte[] rfData) {
    224                this.rfData = rfData;
    225        }
    226
    227        /**
    228         * Returns the received RF data.
    229         *
    230         * @return Received RF data.
    231         */
    232        public byte[] getRFData() {
    233                return rfData;
    234        }
    235
    236        /*
    237         * (non-Javadoc)
    238         * @see com.digi.xbee.api.packet.XBeeAPIPacket#getAPIPacketParameters()
    239         */
    240        @Override
    241        public LinkedHashMap<String, String> getAPIPacketParameters() {
    242                LinkedHashMap<String, String> parameters = new LinkedHashMap<String, String>();
    243                parameters.put("64-bit source address", HexUtils.prettyHexString(sourceAddress64.toString()));
    244                parameters.put("16-bit source address", HexUtils.prettyHexString(sourceAddress16.toString()));
    245                parameters.put("Receive options", HexUtils.prettyHexString(HexUtils.integerToHexString(receiveOptions, 1)));
    246                if (rfData != null)
    247                        parameters.put("RF data", HexUtils.prettyHexString(HexUtils.byteArrayToHexString(rfData)));
    248                return parameters;
    249        }
    250}