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 return get16bitDestinationAddress().equals(XBee16BitAddress.BROADCAST_ADDRESS); 170 } 171 172 /** 173 * Returns the 16-bit destination address. 174 * 175 * @return The 16-bit destination address. 176 * 177 * @see com.digi.xbee.api.models.XBee16BitAddress 178 */ 179 public XBee16BitAddress get16bitDestinationAddress() { 180 return destAddress16; 181 } 182 183 /** 184 * Returns the transmit options bitfield. 185 * 186 * @return Transmit options bitfield. 187 * 188 * @see com.digi.xbee.api.models.XBeeTransmitOptions 189 */ 190 public int getTransmitOptions() { 191 return transmitOptions; 192 } 193 194 /** 195 * Sets the RF data to send. 196 * 197 * @param rfData RF Data to send. 198 */ 199 public void setRFData(byte[] rfData) { 200 this.rfData = rfData; 201 } 202 203 /** 204 * Returns the RF Data to send. 205 * 206 * @return RF data to send. 207 */ 208 public byte[] getRFData() { 209 return rfData; 210 } 211 212 /* 213 * (non-Javadoc) 214 * @see com.digi.xbee.api.packet.XBeeAPIPacket#getAPIPacketParameters() 215 */ 216 @Override 217 public LinkedHashMap<String, String> getAPIPacketParameters() { 218 LinkedHashMap<String, String> parameters = new LinkedHashMap<String, String>(); 219 parameters.put("16-bit dest. address", HexUtils.prettyHexString(destAddress16.toString())); 220 parameters.put("Options", HexUtils.prettyHexString(HexUtils.integerToHexString(transmitOptions, 1))); 221 if (rfData != null) 222 parameters.put("RF data", HexUtils.prettyHexString(HexUtils.byteArrayToHexString(rfData))); 223 return parameters; 224 } 225}