    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.LinkedHashMap;
    017
    018import org.slf4j.Logger;
    019import org.slf4j.LoggerFactory;
    020
    021import com.digi.xbee.api.models.XBee16BitAddress;
    022import com.digi.xbee.api.models.XBeeDiscoveryStatus;
    023import com.digi.xbee.api.models.XBeeTransmitStatus;
    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 Transmit Status Packet. Packet is built using the
    030 * parameters of the constructor or providing a valid API payload.
    031 *
    032 * <p>When a Transmit Request is completed, the module sends a Transmit Status
    033 * message. This message will indicate if the packet was transmitted
    034 * successfully or if there was a failure.</p>
    035 *
    036 * <p>This packet is the response to standard and explicit transmit requests.
    037 * </p>
    038 *
    039 * @see TransmitPacket
    040 */
    041public class TransmitStatusPacket extends XBeeAPIPacket {
    042
    043        // Constants.
    044        private static final int MIN_API_PAYLOAD_LENGTH = 7; // 1 (Frame type) + 1 (frame ID) + 2 (16-bit address) + 1 (retry count) + 1 (delivery status) + 1 (discovery status)
    045
    046        // Variables.
    047        private final XBee16BitAddress destAddress16;
    048
    049        private final int tranmistRetryCount;
    050        private final XBeeTransmitStatus transmitStatus;
    051        private final XBeeDiscoveryStatus discoveryStatus;
    052
    053        private Logger logger;
    054
    055        /**
    056         * Creates a new {@code TransmitStatusPacket} object from the given payload.
    057         *
    058         * @param payload The API frame payload. It must start with the frame type
    059         *                corresponding to a Transmit Status packet ({@code 0x8B}).
    060         *                The byte array must be in {@code OperatingMode.API} mode.
    061         *
    062         * @return Parsed Transmit Status packet.
    063         *
    064         * @throws IllegalArgumentException if {@code payload[0] != APIFrameType.TRANSMIT_STATUS.getValue()} or
    065         *                                  if {@code payload.length < }{@value #MIN_API_PAYLOAD_LENGTH} or
    066         *                                  if {@code frameID < 0} or
    067         *                                  if {@code frameID > 255} or
    068         *                                  if {@code tranmistRetryCount < 0} or
    069         *                                  if {@code tranmistRetryCount > 255}.
    070         * @throws NullPointerException if {@code payload == null}.
    071         */
    072        public static TransmitStatusPacket createPacket(byte[] payload) {
    073                if (payload == null)
    074                        throw new NullPointerException("Transmit Status packet payload cannot be null.");
    075
    076                // 1 (Frame type) + 1 (frame ID) + 2 (16-bit address) + 1 (retry count) + 1 (delivery status) + 1 (discovery status)
    077                if (payload.length < MIN_API_PAYLOAD_LENGTH)
    078                        throw new IllegalArgumentException("Incomplete Transmit Status packet.");
    079
    080                if ((payload[0] & 0xFF) != APIFrameType.TRANSMIT_STATUS.getValue())
    081                        throw new IllegalArgumentException("Payload is not a Transmit Status packet.");
    082
    083                // payload[0] is the frame type.
    084                int index = 1;
    085
    086                // Frame ID byte.
    087                int frameID = payload[index] & 0xFF;
    088                index = index + 1;
    089
    090                // 2 bytes of 16-bit address.
    091                XBee16BitAddress address = new XBee16BitAddress(payload[index] & 0xFF, payload[index + 1] & 0xFF);
    092                index = index + 2;
    093
    094                // Retry count byte.
    095                int retryCount = payload[index] & 0xFF;
    096                index = index + 1;
    097
    098                // Delivery status byte.
    099                int deliveryStatus = payload[index] & 0xFF;
    100                index = index + 1;
    101
    102                // Discovery status byte.
    103                int discoveryStatus = payload[index] & 0xFF;
    104
    105                // TODO if XBeeTransmitStatus is unknown????
    106                return new TransmitStatusPacket(frameID, address, retryCount,
    107                                XBeeTransmitStatus.get(deliveryStatus), XBeeDiscoveryStatus.get(discoveryStatus));
    108        }
    109
    110        /**
    111         * Class constructor. Instantiates a new {@code TransmitStatusPacket}
    112         * object with the given parameters.
    113         *
    114         * @param frameID Frame ID.
    115         * @param destAddress16 16-bit Network address the packet was delivered to.
    116         * @param tranmistRetryCount The number of application transmission retries
    117         *                           that took place.
    118         * @param transmitStatus Transmit status.
    119         * @param discoveryStatus Discovery status.
    120         *
    121         * @throws IllegalArgumentException if {@code frameID < 0} or
    122         *                                  if {@code frameID > 255} or
    123         *                                  if {@code tranmistRetryCount < 0} or
    124         *                                  if {@code tranmistRetryCount > 255}.
    125         * @throws NullPointerException if {@code destAddress16 == null} or
    126         *                              if {@code transmitStatus == null} or
    127         *                              if {@code discoveryStatus == null}.
    128         *
    129         * @see com.digi.xbee.api.models.XBeeDiscoveryStatus
    130         * @see com.digi.xbee.api.models.XBeeTransmitStatus
    131         * @see com.digi.xbee.api.models.XBee16BitAddress
    132         */
    133        public TransmitStatusPacket(int frameID, XBee16BitAddress destAddress16, int tranmistRetryCount,
    134                        XBeeTransmitStatus transmitStatus, XBeeDiscoveryStatus discoveryStatus) {
    135                super(APIFrameType.TRANSMIT_STATUS);
    136
    137                if (destAddress16 == null)
    138                        throw new NullPointerException("16-bit destination address cannot be null.");
    139                if (transmitStatus == null)
    140                        throw new NullPointerException("Delivery status cannot be null.");
    141                if (discoveryStatus == null)
    142                        throw new NullPointerException("Discovery status cannot be null.");
    143                if (frameID < 0 || frameID > 255)
    144                        throw new IllegalArgumentException("Frame ID must be between 0 and 255.");
    145                if (tranmistRetryCount < 0 || tranmistRetryCount > 255)
    146                        throw new IllegalArgumentException("Transmit retry count must be between 0 and 255.");
    147
    148                this.frameID = frameID;
    149                this.destAddress16 = destAddress16;
    150                this.tranmistRetryCount = tranmistRetryCount;
    151                this.transmitStatus = transmitStatus;
    152                this.discoveryStatus = discoveryStatus;
    153                this.logger = LoggerFactory.getLogger(TransmitStatusPacket.class);
    154        }
    155
    156        /*
    157         * (non-Javadoc)
    158         * @see com.digi.xbee.api.packet.XBeeAPIPacket#getAPIPacketSpecificData()
    159         */
    160        @Override
    161        protected byte[] getAPIPacketSpecificData() {
    162                ByteArrayOutputStream data = new ByteArrayOutputStream();
    163                try {
    164                        data.write(destAddress16.getValue());
    165                        data.write(tranmistRetryCount);
    166                        data.write(transmitStatus.getId());
    167                        data.write(discoveryStatus.getId());
    168                } catch (IOException e) {
    169                        logger.error(e.getMessage(), e);
    170                }
    171                return data.toByteArray();
    172        }
    173
    174        /*
    175         * (non-Javadoc)
    176         * @see com.digi.xbee.api.packet.XBeeAPIPacket#needsAPIFrameID()
    177         */
    178        @Override
    179        public boolean needsAPIFrameID() {
    180                return true;
    181        }
    182
    183        /**
    184         * Returns the 16-bit destination address.
    185         *
    186         * @return The 16-bit destination address.
    187         *
    188         * @see com.digi.xbee.api.models.XBee16BitAddress
    189         */
    190        public XBee16BitAddress get16bitDestinationAddress() {
    191                return destAddress16;
    192        }
    193
    194        /**
    195         * Returns the transmit retry count.
    196         *
    197         * @return Transmit retry count.
    198         */
    199        public int getTransmitRetryCount() {
    200                return tranmistRetryCount;
    201        }
    202
    203        /**
    204         * Returns the transmit status.
    205         *
    206         * @return Transmit status.
    207         *
    208         * @see com.digi.xbee.api.models.XBeeTransmitStatus
    209         */
    210        public XBeeTransmitStatus getTransmitStatus() {
    211                return transmitStatus;
    212        }
    213
    214        /**
    215         * Returns the discovery status.
    216         *
    217         * @return Discovery status.
    218         *
    219         * @see XBeeDiscoveryStatus
    220         */
    221        public XBeeDiscoveryStatus getDiscoveryStatus() {
    222                return discoveryStatus;
    223        }
    224
    225        /*
    226         * (non-Javadoc)
    227         * @see com.digi.xbee.api.packet.XBeeAPIPacket#getAPIPacketParameters()
    228         */
    229        @Override
    230        public LinkedHashMap<String, String> getAPIPacketParameters() {
    231                LinkedHashMap<String, String> parameters = new LinkedHashMap<String, String>();
    232                parameters.put("16-bit dest. address", HexUtils.prettyHexString(destAddress16.toString()));
    233                parameters.put("Tx. retry count", HexUtils.prettyHexString(HexUtils.integerToHexString(tranmistRetryCount, 1)) + " (" + tranmistRetryCount + ")");
    234                parameters.put("Delivery status", HexUtils.prettyHexString(HexUtils.integerToHexString(transmitStatus.getId(), 1)) + " (" + transmitStatus.getDescription() + ")");
    235                parameters.put("Discovery status", HexUtils.prettyHexString(HexUtils.integerToHexString(discoveryStatus.getId(), 1)) + " (" + discoveryStatus.getDescription() + ")");
    236                return parameters;
    237        }
    238}