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