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#isBroadcast() 228 */ 229 @Override 230 public boolean isBroadcast() { 231 return false; 232 } 233 234 /* 235 * (non-Javadoc) 236 * @see com.digi.xbee.api.packet.XBeeAPIPacket#getAPIPacketParameters() 237 */ 238 @Override 239 public LinkedHashMap<String, String> getAPIPacketParameters() { 240 LinkedHashMap<String, String> parameters = new LinkedHashMap<String, String>(); 241 parameters.put("16-bit dest. address", HexUtils.prettyHexString(destAddress16.toString())); 242 parameters.put("Tx. retry count", HexUtils.prettyHexString(HexUtils.integerToHexString(tranmistRetryCount, 1)) + " (" + tranmistRetryCount + ")"); 243 parameters.put("Delivery status", HexUtils.prettyHexString(HexUtils.integerToHexString(transmitStatus.getId(), 1)) + " (" + transmitStatus.getDescription() + ")"); 244 parameters.put("Discovery status", HexUtils.prettyHexString(HexUtils.integerToHexString(discoveryStatus.getId(), 1)) + " (" + discoveryStatus.getDescription() + ")"); 245 return parameters; 246 } 247}