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