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.models; 013 014import java.util.LinkedList; 015 016import com.digi.xbee.api.RemoteXBeeDevice; 017import com.digi.xbee.api.packet.APIFrameType; 018import com.digi.xbee.api.packet.XBeeAPIPacket; 019import com.digi.xbee.api.packet.XBeePacket; 020import com.digi.xbee.api.packet.common.ReceivePacket; 021import com.digi.xbee.api.packet.common.RemoteATCommandResponsePacket; 022import com.digi.xbee.api.packet.raw.RX16IOPacket; 023import com.digi.xbee.api.packet.raw.RX16Packet; 024import com.digi.xbee.api.packet.raw.RX64IOPacket; 025import com.digi.xbee.api.packet.raw.RX64Packet; 026 027/** 028 * This class represents a queue of XBee packets used for sequential packets 029 * reading within the XBee Java API. 030 * 031 * <p>The class provides some methods to get specific packet types from 032 * different source nodes.</p> 033 * 034 * @see com.digi.xbee.api.packet.XBeePacket 035 */ 036public class XBeePacketsQueue { 037 038 // Constants. 039 /** 040 * Default maximum number of packets to store in the queue 041 * (value: {@value}). 042 */ 043 public static final int DEFAULT_MAX_LENGTH = 50; 044 045 // Variables. 046 private int maxLength = DEFAULT_MAX_LENGTH; 047 048 private LinkedList<XBeePacket> packetsList; 049 050 /** 051 * Class constructor. Instantiates a new object of type 052 * {@code XBeePacketsQueue}. 053 */ 054 public XBeePacketsQueue() { 055 this(DEFAULT_MAX_LENGTH); 056 } 057 058 /** 059 * Class constructor. Instantiates a new object of type 060 * {@code XBeePacketsQueue} with the given maximum length. 061 * 062 * @param maxLength Maximum length of the queue. 063 * 064 * @throws IllegalArgumentException if {@code maxLength < 1}. 065 */ 066 public XBeePacketsQueue(int maxLength) { 067 if (maxLength < 1) 068 throw new IllegalArgumentException("Queue length must be greater than 0."); 069 070 this.maxLength = maxLength; 071 packetsList = new LinkedList<XBeePacket>(); 072 } 073 074 /** 075 * Adds the provided packet to the list of packets. If the queue is full 076 * the first packet will be discarded to add the given one. 077 * 078 * @param xbeePacket The XBee packet to be added to the list. 079 * 080 * @see com.digi.xbee.api.packet.XBeePacket 081 */ 082 public void addPacket(XBeePacket xbeePacket) { 083 if (packetsList.size() == maxLength) 084 packetsList.removeFirst(); 085 packetsList.add(xbeePacket); 086 } 087 088 /** 089 * Clears the list of packets. 090 */ 091 public void clearQueue() { 092 packetsList.clear(); 093 } 094 095 /** 096 * Returns the first packet from the queue waiting up to the specified 097 * timeout if necessary for an XBee packet to become available. 098 * {@code null }if the queue is empty. 099 * 100 * @param timeout The time in milliseconds to wait for an XBee packet to 101 * become available. 0 to return immediately. 102 * @return The first packet from the queue, {@code null} if it is empty. 103 * 104 * @see com.digi.xbee.api.packet.XBeePacket 105 */ 106 public XBeePacket getFirstPacket(int timeout) { 107 if (timeout > 0) { 108 XBeePacket xbeePacket = getFirstPacket(0); 109 // Wait for a timeout or until an XBee packet is read. 110 Long deadLine = System.currentTimeMillis() + timeout; 111 while (xbeePacket == null && deadLine > System.currentTimeMillis()) { 112 sleep(100); 113 xbeePacket = getFirstPacket(0); 114 } 115 return xbeePacket; 116 } else if (!packetsList.isEmpty()) 117 return packetsList.pop(); 118 return null; 119 } 120 121 /** 122 * Returns the first packet from the queue whose 64-bit source address 123 * matches the address of the provided remote XBee device. 124 * 125 * <p>The methods waits up to the specified timeout if necessary for an 126 * XBee packet to become available. Null if the queue is empty or there is 127 * not any XBee packet sent by the provided remote XBee device.</p> 128 * 129 * @param remoteXBeeDevice The remote XBee device containing the 64-bit 130 * address to look for in the list of packets. 131 * @param timeout The time in milliseconds to wait for an XBee packet from 132 * the specified remote XBee device to become available. 133 * 0 to return immediately. 134 * 135 * @return The first XBee packet whose 64-bit address matches the address 136 * of the provided remote XBee device. {@code null} if no packets 137 * from the specified XBee device are found in the queue. 138 * 139 * @see com.digi.xbee.api.RemoteXBeeDevice 140 * @see com.digi.xbee.api.packet.XBeePacket 141 */ 142 public XBeePacket getFirstPacketFrom(RemoteXBeeDevice remoteXBeeDevice, int timeout) { 143 if (timeout > 0) { 144 XBeePacket xbeePacket = getFirstPacketFrom(remoteXBeeDevice, 0); 145 // Wait for a timeout or until an XBee packet from remoteXBeeDevice is read. 146 Long deadLine = System.currentTimeMillis() + timeout; 147 while (xbeePacket == null && deadLine > System.currentTimeMillis()) { 148 sleep(100); 149 xbeePacket = getFirstPacketFrom(remoteXBeeDevice, 0); 150 } 151 return xbeePacket; 152 } else { 153 for (int i = 0; i < packetsList.size(); i++) { 154 XBeePacket xbeePacket = packetsList.get(i); 155 if (addressesMatch(xbeePacket, remoteXBeeDevice)) 156 return packetsList.remove(i); 157 } 158 } 159 return null; 160 } 161 162 /** 163 * Returns the first data packet from the queue waiting up to the 164 * specified timeout if necessary for an XBee data packet to become 165 * available. {@code null} if the queue is empty or there is not any data 166 * packet inside. 167 * 168 * @param timeout The time in milliseconds to wait for an XBee data packet 169 * to become available. 0 to return immediately. 170 * 171 * @return The first data packet from the queue, {@code null} if it is 172 * empty or no data packets are contained in the queue. 173 * 174 * @see com.digi.xbee.api.packet.XBeePacket 175 */ 176 public XBeePacket getFirstDataPacket(int timeout) { 177 if (timeout > 0) { 178 XBeePacket xbeePacket = getFirstDataPacket(0); 179 // Wait for a timeout or until a data XBee packet is read. 180 Long deadLine = System.currentTimeMillis() + timeout; 181 while (xbeePacket == null && deadLine > System.currentTimeMillis()) { 182 sleep(100); 183 xbeePacket = getFirstDataPacket(0); 184 } 185 return xbeePacket; 186 } else { 187 for (int i = 0; i < packetsList.size(); i++) { 188 XBeePacket xbeePacket = packetsList.get(i); 189 if (isDataPacket(xbeePacket)) 190 return packetsList.remove(i); 191 } 192 } 193 return null; 194 } 195 196 /** 197 * Returns the first data packet from the queue whose 64-bit source 198 * address matches the address of the provided remote XBee device. 199 * 200 * <p>The methods waits up to the specified timeout if necessary for an 201 * XBee data packet to become available. {@code null} if the queue is 202 * empty or there is not any XBee data packet sent by the provided remote 203 * XBee device.</p> 204 * 205 * @param remoteXBeeDevice The XBee device containing the 64-bit address 206 * to look for in the list of packets. 207 * @param timeout The time in milliseconds to wait for an XBee data packet 208 * from the specified remote XBee device to become 209 * available. 0 to return immediately. 210 * 211 * @return The first XBee data packet whose its 64-bit address matches the 212 * address of the provided remote XBee device. {@code null} if no 213 * data packets from the specified XBee device are found in the 214 * queue. 215 * 216 * @see com.digi.xbee.api.RemoteXBeeDevice 217 * @see com.digi.xbee.api.packet.XBeePacket 218 */ 219 public XBeePacket getFirstDataPacketFrom(RemoteXBeeDevice remoteXBeeDevice, int timeout) { 220 if (timeout > 0) { 221 XBeePacket xbeePacket = getFirstDataPacketFrom(remoteXBeeDevice, 0); 222 // Wait for a timeout or until an XBee packet from remoteXBeeDevice is read. 223 Long deadLine = System.currentTimeMillis() + timeout; 224 while (xbeePacket == null && deadLine > System.currentTimeMillis()) { 225 sleep(100); 226 xbeePacket = getFirstDataPacketFrom(remoteXBeeDevice, 0); 227 } 228 return xbeePacket; 229 } else { 230 for (int i = 0; i < packetsList.size(); i++) { 231 XBeePacket xbeePacket = packetsList.get(i); 232 if (isDataPacket(xbeePacket) && addressesMatch(xbeePacket, remoteXBeeDevice)) 233 return packetsList.remove(i); 234 } 235 } 236 return null; 237 } 238 239 /** 240 * Returns whether or not the source address of the provided XBee packet 241 * matches the address of the given remote XBee device. 242 * 243 * @param xbeePacket The XBee packet to compare its address with the 244 * remote XBee device. 245 * @param remoteXBeeDevice The remote XBee device to compare its address 246 * with the XBee packet. 247 * 248 * @return {@code true} if the source address of the provided packet (if 249 * it has) matches the address of the remote XBee device. 250 * 251 * @see com.digi.xbee.api.RemoteXBeeDevice 252 * @see com.digi.xbee.api.packet.XBeePacket 253 */ 254 private boolean addressesMatch(XBeePacket xbeePacket, RemoteXBeeDevice remoteXBeeDevice) { 255 if (!(xbeePacket instanceof XBeeAPIPacket)) 256 return false; 257 APIFrameType packetType = ((XBeeAPIPacket)xbeePacket).getFrameType(); 258 switch (packetType) { 259 case RECEIVE_PACKET: 260 if (remoteXBeeDevice.get64BitAddress() != null && ((ReceivePacket)xbeePacket).get64bitSourceAddress().equals(remoteXBeeDevice.get64BitAddress())) 261 return true; 262 if (remoteXBeeDevice.get16BitAddress() != null && ((ReceivePacket)xbeePacket).get16bitSourceAddress().equals(remoteXBeeDevice.get16BitAddress())) 263 return true; 264 break; 265 case REMOTE_AT_COMMAND_RESPONSE: 266 if (remoteXBeeDevice.get64BitAddress() != null && ((RemoteATCommandResponsePacket)xbeePacket).get64bitSourceAddress().equals(remoteXBeeDevice.get64BitAddress())) 267 return true; 268 if (remoteXBeeDevice.get16BitAddress() != null && ((RemoteATCommandResponsePacket)xbeePacket).get16bitSourceAddress().equals(remoteXBeeDevice.get16BitAddress())) 269 return true; 270 break; 271 case RX_16: 272 if (((RX16Packet)xbeePacket).get16bitSourceAddress().equals(remoteXBeeDevice.get16BitAddress())) 273 return true; 274 break; 275 case RX_64: 276 if (((RX64Packet)xbeePacket).get64bitSourceAddress().equals(remoteXBeeDevice.get64BitAddress())) 277 return true; 278 break; 279 case RX_IO_16: 280 if (((RX16IOPacket)xbeePacket).get16bitSourceAddress().equals(remoteXBeeDevice.get16BitAddress())) 281 return true; 282 break; 283 case RX_IO_64: 284 if (((RX64IOPacket)xbeePacket).get64bitSourceAddress().equals(remoteXBeeDevice.get64BitAddress())) 285 return true; 286 break; 287 default: 288 return false; 289 } 290 return false; 291 } 292 293 /** 294 * Returns whether or not the given XBee packet is a data packet. 295 * 296 * @param xbeePacket The XBee packet to check if is data packet. 297 * 298 * @return {@code true} if the XBee packet is a data packet, {@code false} 299 * otherwise. 300 * 301 * @see com.digi.xbee.api.packet.XBeePacket 302 */ 303 private boolean isDataPacket(XBeePacket xbeePacket) { 304 if (!(xbeePacket instanceof XBeeAPIPacket)) 305 return false; 306 APIFrameType packetType = ((XBeeAPIPacket)xbeePacket).getFrameType(); 307 switch (packetType) { 308 case RECEIVE_PACKET: 309 case RX_16: 310 case RX_64: 311 return true; 312 default: 313 return false; 314 } 315 } 316 317 /** 318 * Sleeps the thread for the given number of milliseconds. 319 * 320 * @param milliseconds The number of milliseconds that the thread should 321 * be sleeping. 322 */ 323 private void sleep(int milliseconds) { 324 try { 325 Thread.sleep(milliseconds); 326 } catch (InterruptedException e) { } 327 } 328 329 /** 330 * Returns the maximum size of the XBee packets queue. 331 * 332 * @return The maximum size of the XBee packets queue. 333 */ 334 public int getMaxSize() { 335 return maxLength; 336 } 337 338 /** 339 * Returns the current size of the XBee packets queue. 340 * 341 * @return The current size of the XBee packets queue. 342 */ 343 public int getCurrentSize() { 344 return packetsList.size(); 345 } 346}