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