    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.raw;
    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.XBee64BitAddress;
    023import com.digi.xbee.api.packet.XBeeAPIPacket;
    024import com.digi.xbee.api.packet.APIFrameType;
    025import com.digi.xbee.api.utils.ByteUtils;
    026import com.digi.xbee.api.utils.HexUtils;
    027
    028/**
    029 * This class represents an RX (Receive) 64 Request packet. Packet is built
    030 * using the parameters of the constructor or providing a valid API payload.
    031 *
    032 * <p>When the module receives an RF packet, it is sent out the UART using
    033 * this message type.</p>
    034 *
    035 * <p>This packet is the response to TX (transmit) 64 Request packets.</p>
    036 *
    037 * @see TX64Packet
    038 * @see com.digi.xbee.api.packet.XBeeAPIPacket
    039 *
    040 */
    041public class RX64Packet extends XBeeAPIPacket {
    042
    043        // Constants.
    044        private static final int MIN_API_PAYLOAD_LENGTH = 11; // 1 (Frame type) + 8 (64-bit address) + 1 (signal strength) + 1 (receive options)
    045
    046        // Variables.
    047        private final XBee64BitAddress sourceAddress64;
    048
    049        private final int rssi;
    050        private final int receiveOptions;
    051
    052        private byte[] rfData;
    053
    054        private Logger logger;
    055
    056        /**
    057         * Creates a new {@code RX64Packet} object from the given payload.
    058         *
    059         * @param payload The API frame payload. It must start with the frame type
    060         *                corresponding to a RX64 packet ({@code 0x80}).
    061         *                The byte array must be in {@code OperatingMode.API} mode.
    062         *
    063         * @return Parsed RX 64 packet.
    064         *
    065         * @throws IllegalArgumentException if {@code payload[0] != APIFrameType.RX_64.getValue()} or
    066         *                                  if {@code payload.length < }{@value #MIN_API_PAYLOAD_LENGTH} or
    067         *                                  if {@code rssi < 0} or
    068         *                                  if {@code rssi > 100} or
    069         *                                  if {@code receiveOptions < 0} or
    070         *                                  if {@code receiveOptions > 255}.
    071         * @throws NullPointerException if {@code payload == null}.
    072         */
    073        public static RX64Packet createPacket(byte[] payload) {
    074                if (payload == null)
    075                        throw new NullPointerException("RX64 packet payload cannot be null.");
    076
    077                // 1 (Frame type) + 8 (64-bit address) + 1 (signal strength) + 1 (receive options)
    078                if (payload.length < MIN_API_PAYLOAD_LENGTH)
    079                        throw new IllegalArgumentException("Incomplete RX64 packet.");
    080
    081                if ((payload[0] & 0xFF) != APIFrameType.RX_64.getValue())
    082                        throw new IllegalArgumentException("Payload is not a RX64 packet.");
    083
    084                // payload[0] is the frame type.
    085                int index = 1;
    086
    087                // 8 bytes of 64-bit address.
    088                XBee64BitAddress sourceAddress64 = new XBee64BitAddress(Arrays.copyOfRange(payload, index, index + 8));
    089                index = index + 8;
    090
    091                // Signal strength byte.
    092                int signalStrength = payload[index] & 0xFF;
    093                index = index + 1;
    094
    095                // Receive options byte.
    096                int receiveOptions = payload[index] & 0xFF;
    097                index = index + 1;
    098
    099                // Get data.
    100                byte[] data = null;
    101                if (index < payload.length)
    102                        data = Arrays.copyOfRange(payload, index, payload.length);
    103
    104                return new RX64Packet(sourceAddress64, signalStrength, receiveOptions, data);
    105        }
    106
    107        /**
    108         * Class constructor. Instantiates a new {@code RX64Packet} object with
    109         * the given parameters.
    110         *
    111         * @param sourceAddress64 64-bit address of the sender.
    112         * @param rssi Received signal strength indicator.
    113         * @param receiveOptions Bitfield indicating the receive options.
    114         * @param rfData Received RF data.
    115         *
    116         * @throws IllegalArgumentException if {@code rssi < 0} or
    117         *                                  if {@code rssi > 100} or
    118         *                                  if {@code receiveOptions < 0} or
    119         *                                  if {@code receiveOptions > 255}.
    120         * @throws NullPointerException if {@code sourceAddress64 == null}.
    121         *
    122         * @see com.digi.xbee.api.models.XBeeReceiveOptions
    123         * @see com.digi.xbee.api.models.XBee64BitAddress
    124         */
    125        public RX64Packet(XBee64BitAddress sourceAddress64, int rssi, int receiveOptions, byte[] rfData) {
    126                super(APIFrameType.RX_64);
    127
    128                if (sourceAddress64 == null)
    129                        throw new NullPointerException("64-bit source address cannot be null.");
    130                if (rssi < 0 || rssi > 100)
    131                        throw new IllegalArgumentException("RSSI value must be between 0 and 100.");
    132                if (receiveOptions < 0 || receiveOptions > 255)
    133                        throw new IllegalArgumentException("Receive options value must be between 0 and 255.");
    134
    135                this.sourceAddress64 = sourceAddress64;
    136                this.rssi = rssi;
    137                this.receiveOptions = receiveOptions;
    138                this.rfData = rfData;
    139                this.logger = LoggerFactory.getLogger(RX64Packet.class);
    140        }
    141
    142        /*
    143         * (non-Javadoc)
    144         * @see com.digi.xbee.api.packet.XBeeAPIPacket#getAPIPacketSpecificData()
    145         */
    146        @Override
    147        protected byte[] getAPIPacketSpecificData() {
    148                ByteArrayOutputStream os = new ByteArrayOutputStream();
    149                try {
    150                        os.write(sourceAddress64.getValue());
    151                        os.write(rssi);
    152                        os.write(receiveOptions);
    153                        if (rfData != null)
    154                                os.write(rfData);
    155                } catch (IOException e) {
    156                        logger.error(e.getMessage(), e);
    157                }
    158                return os.toByteArray();
    159        }
    160
    161        /*
    162         * (non-Javadoc)
    163         * @see com.digi.xbee.api.packet.XBeeAPIPacket#needsAPIFrameID()
    164         */
    165        @Override
    166        public boolean needsAPIFrameID() {
    167                return false;
    168        }
    169
    170        /*
    171         * (non-Javadoc)
    172         * @see com.digi.xbee.api.packet.XBeeAPIPacket#isBroadcast()
    173         */
    174        @Override
    175        public boolean isBroadcast() {
    176                if (ByteUtils.isBitEnabled(getReceiveOptions(), 1)
    177                                || ByteUtils.isBitEnabled(getReceiveOptions(), 2))
    178                        return true;
    179                return false;
    180        }
    181
    182        /**
    183         * Returns the 64-bit sender/source address.
    184         *
    185         * @return The 64-bit sender/source address.
    186         *
    187         * @see com.digi.xbee.api.models.XBee64BitAddress
    188         */
    189        public XBee64BitAddress get64bitSourceAddress() {
    190                return sourceAddress64;
    191        }
    192
    193        /**
    194         * Returns the Received Signal Strength Indicator (RSSI).
    195         *
    196         * @return The Received Signal Strength Indicator (RSSI).
    197         */
    198        public int getRSSI() {
    199                return rssi;
    200        }
    201
    202        /**
    203         * Returns the receive options bitfield.
    204         *
    205         * @return Receive options bitfield.
    206         *
    207         * @see com.digi.xbee.api.models.XBeeReceiveOptions
    208         */
    209        public int getReceiveOptions() {
    210                return receiveOptions;
    211        }
    212
    213        /**
    214         * Sets the received RF data.
    215         *
    216         * @param rfData Received RF data.
    217         */
    218        public void setRFData(byte[] rfData) {
    219                this.rfData = rfData;
    220        }
    221
    222        /**
    223         * Returns the received RF data.
    224         *
    225         * @return Received RF data.
    226         */
    227        public byte[] getRFData() {
    228                return rfData;
    229        }
    230
    231        /*
    232         * (non-Javadoc)
    233         * @see com.digi.xbee.api.packet.XBeeAPIPacket#getAPIPacketParameters()
    234         */
    235        @Override
    236        public LinkedHashMap<String, String> getAPIPacketParameters() {
    237                LinkedHashMap<String, String> parameters = new LinkedHashMap<String, String>();
    238                parameters.put("64-bit source address", HexUtils.prettyHexString(sourceAddress64.toString()));
    239                parameters.put("RSSI", HexUtils.prettyHexString(HexUtils.integerToHexString(rssi, 1)));
    240                parameters.put("Options", HexUtils.prettyHexString(HexUtils.integerToHexString(receiveOptions, 1)));
    241                if (rfData != null)
    242                        parameters.put("RF data", HexUtils.prettyHexString(HexUtils.byteArrayToHexString(rfData)));
    243                return parameters;
    244        }
    245}