001/* 002 * Copyright 2017-2022, Digi International Inc. 003 * 004 * This Source Code Form is subject to the terms of the Mozilla Public 005 * License, v. 2.0. If a copy of the MPL was not distributed with this 006 * file, you can obtain one at http://mozilla.org/MPL/2.0/. 007 * 008 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 009 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 010 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 011 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 012 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 013 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 014 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 015 */ 016package com.digi.xbee.api; 017 018import java.io.IOException; 019import java.net.Inet6Address; 020import java.net.UnknownHostException; 021import java.security.NoSuchAlgorithmException; 022import java.util.ArrayList; 023import java.util.Arrays; 024import java.util.Set; 025import java.util.TreeSet; 026 027import org.slf4j.Logger; 028import org.slf4j.LoggerFactory; 029 030import com.digi.xbee.api.connection.IConnectionInterface; 031import com.digi.xbee.api.connection.bluetooth.AbstractBluetoothInterface; 032import com.digi.xbee.api.connection.ConnectionType; 033import com.digi.xbee.api.connection.serial.AbstractSerialPort; 034import com.digi.xbee.api.connection.serial.SerialPortParameters; 035import com.digi.xbee.api.exceptions.ATCommandException; 036import com.digi.xbee.api.exceptions.BluetoothAuthenticationException; 037import com.digi.xbee.api.exceptions.InterfaceAlreadyOpenException; 038import com.digi.xbee.api.exceptions.InterfaceNotOpenException; 039import com.digi.xbee.api.exceptions.InvalidOperatingModeException; 040import com.digi.xbee.api.exceptions.OperationNotSupportedException; 041import com.digi.xbee.api.exceptions.TimeoutException; 042import com.digi.xbee.api.exceptions.TransmitException; 043import com.digi.xbee.api.exceptions.XBeeException; 044import com.digi.xbee.api.io.IOLine; 045import com.digi.xbee.api.io.IOMode; 046import com.digi.xbee.api.io.IOSample; 047import com.digi.xbee.api.io.IOValue; 048import com.digi.xbee.api.listeners.IExplicitDataReceiveListener; 049import com.digi.xbee.api.listeners.IIOSampleReceiveListener; 050import com.digi.xbee.api.listeners.IModemStatusReceiveListener; 051import com.digi.xbee.api.listeners.IIPDataReceiveListener; 052import com.digi.xbee.api.listeners.IPacketReceiveListener; 053import com.digi.xbee.api.listeners.IDataReceiveListener; 054import com.digi.xbee.api.listeners.ISMSReceiveListener; 055import com.digi.xbee.api.listeners.IUserDataRelayReceiveListener; 056import com.digi.xbee.api.listeners.relay.IBluetoothDataReceiveListener; 057import com.digi.xbee.api.listeners.relay.IMicroPythonDataReceiveListener; 058import com.digi.xbee.api.listeners.relay.ISerialDataReceiveListener; 059import com.digi.xbee.api.models.APIOutputMode; 060import com.digi.xbee.api.models.ATCommand; 061import com.digi.xbee.api.models.ATCommandResponse; 062import com.digi.xbee.api.models.ATCommandStatus; 063import com.digi.xbee.api.models.AssociationIndicationStatus; 064import com.digi.xbee.api.models.ExplicitXBeeMessage; 065import com.digi.xbee.api.models.HardwareVersion; 066import com.digi.xbee.api.models.ModemStatusEvent; 067import com.digi.xbee.api.models.PowerLevel; 068import com.digi.xbee.api.models.RemoteATCommandOptions; 069import com.digi.xbee.api.models.RestFulStatusEnum; 070import com.digi.xbee.api.models.XBee16BitAddress; 071import com.digi.xbee.api.models.XBee64BitAddress; 072import com.digi.xbee.api.models.XBeeLocalInterface; 073import com.digi.xbee.api.models.XBeeMessage; 074import com.digi.xbee.api.models.XBeePacketsQueue; 075import com.digi.xbee.api.models.OperatingMode; 076import com.digi.xbee.api.models.XBeeProtocol; 077import com.digi.xbee.api.models.XBeeTransmitOptions; 078import com.digi.xbee.api.models.XBeeTransmitStatus; 079import com.digi.xbee.api.packet.XBeeAPIPacket; 080import com.digi.xbee.api.packet.APIFrameType; 081import com.digi.xbee.api.packet.XBeePacket; 082import com.digi.xbee.api.packet.common.ATCommandPacket; 083import com.digi.xbee.api.packet.common.ATCommandQueuePacket; 084import com.digi.xbee.api.packet.common.ATCommandResponsePacket; 085import com.digi.xbee.api.packet.common.ExplicitAddressingPacket; 086import com.digi.xbee.api.packet.common.ExplicitRxIndicatorPacket; 087import com.digi.xbee.api.packet.common.IODataSampleRxIndicatorPacket; 088import com.digi.xbee.api.packet.common.ReceivePacket; 089import com.digi.xbee.api.packet.common.RemoteATCommandPacket; 090import com.digi.xbee.api.packet.common.RemoteATCommandResponsePacket; 091import com.digi.xbee.api.packet.common.TransmitPacket; 092import com.digi.xbee.api.packet.common.TransmitStatusPacket; 093import com.digi.xbee.api.packet.raw.RX16IOPacket; 094import com.digi.xbee.api.packet.raw.RX16Packet; 095import com.digi.xbee.api.packet.raw.RX64IOPacket; 096import com.digi.xbee.api.packet.raw.RX64Packet; 097import com.digi.xbee.api.packet.raw.TX64Packet; 098import com.digi.xbee.api.packet.raw.TXStatusPacket; 099import com.digi.xbee.api.packet.relay.UserDataRelayPacket; 100import com.digi.xbee.api.packet.thread.CoAPRxResponsePacket; 101import com.digi.xbee.api.packet.thread.CoAPTxRequestPacket; 102import com.digi.xbee.api.packet.thread.IPv6RemoteATCommandRequestPacket; 103import com.digi.xbee.api.packet.thread.IPv6RemoteATCommandResponsePacket; 104import com.digi.xbee.api.utils.ByteUtils; 105import com.digi.xbee.api.utils.HexUtils; 106import com.digi.xbee.api.utils.srp.SrpUtils; 107 108/** 109 * This class provides common functionality for all XBee devices. 110 * 111 * @see XBeeDevice 112 * @see RemoteXBeeDevice 113 */ 114public abstract class AbstractXBeeDevice { 115 116 // Constants. 117 private static String COMMAND_MODE_CHAR = "+"; 118 private static String COMMAND_MODE_OK = "OK\r"; 119 private static String COMMAND_MODE_EXIT = "ATCN\r"; 120 private static String COMMAND_MODE_AP = "ATAP\r"; 121 122 private static int TIMEOUT_RESET = 5000; 123 protected static int TIMEOUT_READ_PACKET = 3000; 124 125 // Variables. 126 protected XBeeNetwork network; 127 128 private Object resetLock = new Object(); 129 130 private boolean modemStatusReceived = false; 131 132 protected String bluetoothPassword; 133 134 /** 135 * Default receive timeout used to wait for a response in synchronous 136 * operations: {@value} ms. 137 * 138 * @see XBeeDevice#getReceiveTimeout() 139 * @see XBeeDevice#setReceiveTimeout(int) 140 */ 141 protected final static int DEFAULT_RECEIVE_TIMETOUT = 2000; // 2.0 seconds of timeout to receive packet and command responses. 142 143 /** 144 * Timeout to wait before entering in command mode: {@value} ms. 145 * 146 * <p>It is used to determine the operating mode of the module (this 147 * library only supports API modes, not transparent mode).</p> 148 * 149 * <p>This value depends on the {@code GT}, {@code AT} and/or {@code BT} 150 * parameters.</p> 151 * 152 * @see XBeeDevice#determineOperatingMode() 153 */ 154 protected final static int TIMEOUT_BEFORE_COMMAND_MODE = 1200; 155 156 /** 157 * Timeout to wait after entering and exiting command mode: {@value} ms. 158 * 159 * <p>It is used to determine the operating mode of the module (this 160 * library only supports API modes, not transparent mode).</p> 161 * 162 * <p>This value depends on the {@code GT}, {@code AT} and/or {@code BT} 163 * parameters.</p> 164 * 165 * @see XBeeDevice#determineOperatingMode() 166 */ 167 protected final static int DEFAULT_GUARD_TIME = 1500; 168 169 // Variables. 170 protected IConnectionInterface connectionInterface; 171 172 protected DataReader dataReader = null; 173 174 protected XBeeProtocol xbeeProtocol = XBeeProtocol.UNKNOWN; 175 176 protected OperatingMode operatingMode = OperatingMode.UNKNOWN; 177 178 protected XBee16BitAddress xbee16BitAddress = XBee16BitAddress.UNKNOWN_ADDRESS; 179 protected XBee64BitAddress xbee64BitAddress = XBee64BitAddress.UNKNOWN_ADDRESS; 180 181 protected Inet6Address ipv6Address = null; 182 183 protected int currentFrameID = 0xFF; 184 protected int receiveTimeout = DEFAULT_RECEIVE_TIMETOUT; 185 186 protected AbstractXBeeDevice localXBeeDevice; 187 188 protected Logger logger; 189 190 private String nodeID; 191 private String firmwareVersion; 192 193 private HardwareVersion hardwareVersion; 194 195 private Object ioLock = new Object(); 196 197 private boolean ioPacketReceived = false; 198 private boolean applyConfigurationChanges = true; 199 200 private byte[] ioPacketPayload; 201 202 /** 203 * Class constructor. Instantiates a new {@code XBeeDevice} object in the 204 * given port name and baud rate. 205 * 206 * @param port Serial port name where XBee device is attached to. 207 * @param baudRate Serial port baud rate to communicate with the device. 208 * Other connection parameters will be set as default (8 209 * data bits, 1 stop bit, no parity, no flow control). 210 * 211 * @throws IllegalArgumentException if {@code baudRate < 0}. 212 * @throws NullPointerException if {@code port == null}. 213 * 214 * @see #AbstractXBeeDevice(IConnectionInterface) 215 * @see #AbstractXBeeDevice(String, SerialPortParameters) 216 * @see #AbstractXBeeDevice(AbstractXBeeDevice, XBee64BitAddress) 217 * @see #AbstractXBeeDevice(AbstractXBeeDevice, XBee64BitAddress, XBee16BitAddress, String) 218 * @see #AbstractXBeeDevice(String, int, int, int, int, int) 219 */ 220 public AbstractXBeeDevice(String port, int baudRate) { 221 this(XBee.createConnectiontionInterface(port, baudRate)); 222 } 223 224 /** 225 * Class constructor. Instantiates a new {@code XBeeDevice} object in the 226 * given serial port name and settings. 227 * 228 * @param port Serial port name where XBee device is attached to. 229 * @param baudRate Serial port baud rate to communicate with the device. 230 * @param dataBits Serial port data bits. 231 * @param stopBits Serial port data bits. 232 * @param parity Serial port data bits. 233 * @param flowControl Serial port data bits. 234 * 235 * @throws IllegalArgumentException if {@code baudRate < 0} or 236 * if {@code dataBits < 0} or 237 * if {@code stopBits < 0} or 238 * if {@code parity < 0} or 239 * if {@code flowControl < 0}. 240 * @throws NullPointerException if {@code port == null}. 241 * 242 * @see #AbstractXBeeDevice(IConnectionInterface) 243 * @see #AbstractXBeeDevice(String, int) 244 * @see #AbstractXBeeDevice(String, SerialPortParameters) 245 * @see #AbstractXBeeDevice(AbstractXBeeDevice, XBee64BitAddress) 246 * @see #AbstractXBeeDevice(AbstractXBeeDevice, XBee64BitAddress, XBee16BitAddress, String) 247 */ 248 public AbstractXBeeDevice(String port, int baudRate, int dataBits, int stopBits, int parity, int flowControl) { 249 this(port, new SerialPortParameters(baudRate, dataBits, stopBits, parity, flowControl)); 250 } 251 252 /** 253 * Class constructor. Instantiates a new {@code XBeeDevice} object in the 254 * given serial port name and parameters. 255 * 256 * @param port Serial port name where XBee device is attached to. 257 * @param serialPortParameters Object containing the serial port parameters. 258 * 259 * @throws NullPointerException if {@code port == null} or 260 * if {@code serialPortParameters == null}. 261 * 262 * @see #AbstractXBeeDevice(IConnectionInterface) 263 * @see #AbstractXBeeDevice(String, int) 264 * @see #AbstractXBeeDevice(AbstractXBeeDevice, XBee64BitAddress) 265 * @see #AbstractXBeeDevice(AbstractXBeeDevice, XBee64BitAddress, XBee16BitAddress, String) 266 * @see #AbstractXBeeDevice(String, int, int, int, int, int) 267 * @see com.digi.xbee.api.connection.serial.SerialPortParameters 268 */ 269 public AbstractXBeeDevice(String port, SerialPortParameters serialPortParameters) { 270 this(XBee.createConnectiontionInterface(port, serialPortParameters)); 271 } 272 273 /** 274 * Class constructor. Instantiates a new {@code XBeeDevice} object with the 275 * given connection interface. 276 * 277 * @param connectionInterface The connection interface with the physical 278 * XBee device. 279 * 280 * @throws NullPointerException if {@code connectionInterface == null}. 281 * 282 * @see #AbstractXBeeDevice(String, int) 283 * @see #AbstractXBeeDevice(String, SerialPortParameters) 284 * @see #AbstractXBeeDevice(AbstractXBeeDevice, XBee64BitAddress) 285 * @see #AbstractXBeeDevice(AbstractXBeeDevice, XBee64BitAddress, XBee16BitAddress, String) 286 * @see #AbstractXBeeDevice(String, int, int, int, int, int) 287 * @see com.digi.xbee.api.connection.IConnectionInterface 288 */ 289 public AbstractXBeeDevice(IConnectionInterface connectionInterface) { 290 if (connectionInterface == null) 291 throw new NullPointerException("ConnectionInterface cannot be null."); 292 293 this.connectionInterface = connectionInterface; 294 this.logger = LoggerFactory.getLogger(this.getClass()); 295 logger.debug(toString() + "Using the connection interface {}.", 296 connectionInterface.getClass().getSimpleName()); 297 } 298 299 /** 300 * Class constructor. Instantiates a new {@code RemoteXBeeDevice} object 301 * with the given local {@code XBeeDevice} which contains the connection 302 * interface to be used. 303 * 304 * @param localXBeeDevice The local XBee device that will behave as 305 * connection interface to communicate with this 306 * remote XBee device. 307 * @param addr64 The 64-bit address to identify this XBee device. 308 * 309 * @throws IllegalArgumentException If {@code localXBeeDevice.isRemote() == true}. 310 * @throws NullPointerException if {@code localXBeeDevice == null} or 311 * if {@code addr64 == null}. 312 * 313 * @see #AbstractXBeeDevice(IConnectionInterface) 314 * @see #AbstractXBeeDevice(String, int) 315 * @see #AbstractXBeeDevice(String, SerialPortParameters) 316 * @see #AbstractXBeeDevice(AbstractXBeeDevice, XBee64BitAddress, XBee16BitAddress, String) 317 * @see #AbstractXBeeDevice(String, int, int, int, int, int) 318 * @see com.digi.xbee.api.models.XBee16BitAddress 319 */ 320 public AbstractXBeeDevice(AbstractXBeeDevice localXBeeDevice, XBee64BitAddress addr64) { 321 this(localXBeeDevice, addr64, null, null); 322 } 323 324 /** 325 * Class constructor. Instantiates a new {@code RemoteXBeeDevice} object 326 * with the given local {@code XBeeDevice} which contains the connection 327 * interface to be used. 328 * 329 * @param localXBeeDevice The local XBee device that will behave as 330 * connection interface to communicate with this 331 * remote XBee device. 332 * @param addr64 The 64-bit address to identify this XBee device. 333 * @param addr16 The 16-bit address to identify this XBee device. It might 334 * be {@code null}. 335 * @param id The node identifier of this XBee device. It might be 336 * {@code null}. 337 * 338 * @throws IllegalArgumentException If {@code localXBeeDevice.isRemote() == true}. 339 * @throws NullPointerException If {@code localXBeeDevice == null} or 340 * if {@code addr64 == null}. 341 * 342 * @see #AbstractXBeeDevice(IConnectionInterface) 343 * @see #AbstractXBeeDevice(String, int) 344 * @see #AbstractXBeeDevice(String, SerialPortParameters) 345 * @see #AbstractXBeeDevice(AbstractXBeeDevice, XBee64BitAddress) 346 * @see #AbstractXBeeDevice(String, int, int, int, int, int) 347 * @see com.digi.xbee.api.models.XBee16BitAddress 348 * @see com.digi.xbee.api.models.XBee64BitAddress 349 */ 350 public AbstractXBeeDevice(AbstractXBeeDevice localXBeeDevice, XBee64BitAddress addr64, 351 XBee16BitAddress addr16, String id) { 352 if (localXBeeDevice == null) 353 throw new NullPointerException("Local XBee device cannot be null."); 354 if (addr64 == null) 355 throw new NullPointerException("XBee 64-bit address of the device cannot be null."); 356 if (localXBeeDevice.isRemote()) 357 throw new IllegalArgumentException("The given local XBee device is remote."); 358 359 this.localXBeeDevice = localXBeeDevice; 360 this.connectionInterface = localXBeeDevice.getConnectionInterface(); 361 this.xbee64BitAddress = addr64; 362 this.xbee16BitAddress = addr16; 363 if (addr16 == null) 364 xbee16BitAddress = XBee16BitAddress.UNKNOWN_ADDRESS; 365 this.nodeID = id; 366 this.logger = LoggerFactory.getLogger(this.getClass()); 367 logger.debug(toString() + "Using the connection interface {}.", 368 connectionInterface.getClass().getSimpleName()); 369 } 370 371 /** 372 * Class constructor. Instantiates a new {@code RemoteXBeeDevice} object 373 * with the given local {@code XBeeDevice} which contains the connection 374 * interface to be used. 375 * 376 * @param localXBeeDevice The local XBee device that will behave as 377 * connection interface to communicate with this 378 * remote XBee device. 379 * @param ipv6Addr The IPv6 address to identify this XBee device. 380 * 381 * @throws IllegalArgumentException If {@code localXBeeDevice.isRemote() == true}. 382 * @throws NullPointerException if {@code localXBeeDevice == null} or 383 * if {@code ipv6Addr == null}. 384 * 385 * @see #AbstractXBeeDevice(IConnectionInterface) 386 * @see #AbstractXBeeDevice(String, int) 387 * @see #AbstractXBeeDevice(String, SerialPortParameters) 388 * @see #AbstractXBeeDevice(String, int, int, int, int, int) 389 * @see java.net.Inet6Address 390 * 391 * @since 1.2.1 392 */ 393 public AbstractXBeeDevice(AbstractXBeeDevice localXBeeDevice, Inet6Address ipv6Addr) { 394 this(localXBeeDevice, ipv6Addr, null); 395 } 396 397 /** 398 * Class constructor. Instantiates a new {@code RemoteXBeeDevice} object 399 * with the given local {@code XBeeDevice} which contains the connection 400 * interface to be used. 401 * 402 * @param localXBeeDevice The local XBee device that will behave as 403 * connection interface to communicate with this 404 * remote XBee device. 405 * @param ipv6Addr The IPv6 address to identify this XBee device. 406 * @param id The node identifier of this XBee device. It might be 407 * {@code null}. 408 * 409 * @throws IllegalArgumentException If {@code localXBeeDevice.isRemote() == true}. 410 * @throws NullPointerException if {@code localXBeeDevice == null} or 411 * if {@code ipv6Addr == null}. 412 * 413 * @see #AbstractXBeeDevice(IConnectionInterface) 414 * @see #AbstractXBeeDevice(String, int) 415 * @see #AbstractXBeeDevice(String, SerialPortParameters) 416 * @see #AbstractXBeeDevice(String, int, int, int, int, int) 417 * @see java.net.Inet6Address 418 * 419 * @since 1.2.1 420 */ 421 public AbstractXBeeDevice(AbstractXBeeDevice localXBeeDevice, Inet6Address ipv6Addr, String id) { 422 if (localXBeeDevice == null) 423 throw new NullPointerException("Local XBee device cannot be null."); 424 if (ipv6Addr == null) 425 throw new NullPointerException("XBee IPv6 address of the device cannot be null."); 426 if (localXBeeDevice.isRemote()) 427 throw new IllegalArgumentException("The given local XBee device is remote."); 428 429 this.localXBeeDevice = localXBeeDevice; 430 this.connectionInterface = localXBeeDevice.getConnectionInterface(); 431 this.ipv6Address = ipv6Addr; 432 this.nodeID = id; 433 this.logger = LoggerFactory.getLogger(this.getClass()); 434 logger.debug(toString() + "Using the connection interface {}.", 435 connectionInterface.getClass().getSimpleName()); 436 } 437 438 /** 439 * Returns the connection interface associated to this XBee device. 440 * 441 * @return XBee device's connection interface. 442 * 443 * @see com.digi.xbee.api.connection.IConnectionInterface 444 */ 445 public IConnectionInterface getConnectionInterface() { 446 return connectionInterface; 447 } 448 449 /** 450 * Returns whether this XBee device is a remote device. 451 * 452 * @return {@code true} if this XBee device is a remote device, 453 * {@code false} otherwise. 454 */ 455 abstract public boolean isRemote(); 456 457 /** 458 * Reads some parameters from this device and obtains its protocol. 459 * 460 * <p>This method refresh the values of:</p> 461 * <ul> 462 * <li>64-bit address only if it is not initialized.</li> 463 * <li>Node Identifier.</li> 464 * <li>Hardware version if it is not initialized.</li> 465 * <li>Firmware version.</li> 466 * <li>XBee device protocol.</li> 467 * <li>16-bit address (not for DigiMesh/DigiPoint modules).</li> 468 * </ul> 469 * 470 * @throws InterfaceNotOpenException if this device connection is not open. 471 * @throws TimeoutException if there is a timeout reading the parameters. 472 * @throws XBeeException if there is any error trying to read the device information or 473 * if there is any other XBee related exception. 474 * 475 * @see #get16BitAddress() 476 * @see #get64BitAddress() 477 * @see #getHardwareVersion() 478 * @see #getNodeID() 479 * @see #getFirmwareVersion() 480 * @see #getXBeeProtocol() 481 * @see #setNodeID(String) 482 */ 483 public void readDeviceInfo() throws TimeoutException, XBeeException { 484 byte[] response = null; 485 // Get the 64-bit address. 486 if (xbee64BitAddress == null || xbee64BitAddress.equals(XBee64BitAddress.UNKNOWN_ADDRESS)) { 487 String addressHigh; 488 String addressLow; 489 490 response = getParameter("SH"); 491 addressHigh = HexUtils.byteArrayToHexString(response); 492 493 response = getParameter("SL"); 494 addressLow = HexUtils.byteArrayToHexString(response); 495 496 while(addressLow.length() < 8) 497 addressLow = "0" + addressLow; 498 499 xbee64BitAddress = new XBee64BitAddress(addressHigh + addressLow); 500 } 501 // Get the Node ID. 502 response = getParameter("NI"); 503 nodeID = new String(response); 504 505 // Get the hardware version. 506 if (hardwareVersion == null) { 507 response = getParameter("HV"); 508 hardwareVersion = HardwareVersion.get(response[0]); 509 } 510 // Get the firmware version. 511 response = getParameter("VR"); 512 firmwareVersion = HexUtils.byteArrayToHexString(response); 513 514 // Original value of the protocol. 515 XBeeProtocol origProtocol = getXBeeProtocol(); 516 517 // Obtain the device protocol. 518 xbeeProtocol = XBeeProtocol.determineProtocol(hardwareVersion, firmwareVersion); 519 520 if (origProtocol != XBeeProtocol.UNKNOWN 521 && origProtocol != xbeeProtocol) { 522 throw new XBeeException("Error reading device information: " 523 + "Your module seems to be " + xbeeProtocol 524 + " and NOT " + origProtocol + ". Check if you are using" 525 + " the appropriate device class."); 526 } 527 528 // Get the 16-bit address. This must be done after obtaining the protocol because 529 // DigiMesh and Point-to-Multipoint protocols don't have 16-bit addresses. 530 XBeeProtocol protocol = getXBeeProtocol(); 531 if (protocol == XBeeProtocol.ZIGBEE 532 || protocol == XBeeProtocol.RAW_802_15_4 533 || protocol == XBeeProtocol.XTEND 534 || protocol == XBeeProtocol.SMART_ENERGY 535 || protocol == XBeeProtocol.ZNET) { 536 response = getParameter("MY"); 537 xbee16BitAddress = new XBee16BitAddress(response); 538 } 539 } 540 541 /** 542 * Returns the 16-bit address of this XBee device. 543 * 544 * <p>To refresh this value use the {@link #readDeviceInfo()} method.</p> 545 * 546 * @return The 16-bit address of this XBee device. 547 * 548 * @see com.digi.xbee.api.models.XBee16BitAddress 549 */ 550 public XBee16BitAddress get16BitAddress() { 551 return xbee16BitAddress; 552 } 553 554 /** 555 * Returns the 64-bit address of this XBee device. 556 * 557 * <p>If this value is {@code null} or 558 * {@code XBee64BitAddress.UNKNOWN_ADDRESS}, use the 559 * {@link #readDeviceInfo()} method to get its value.</p> 560 * 561 * @return The 64-bit address of this XBee device. 562 * 563 * @see com.digi.xbee.api.models.XBee64BitAddress 564 */ 565 public XBee64BitAddress get64BitAddress() { 566 return xbee64BitAddress; 567 } 568 569 /** 570 * Returns the IPv6 address of this IPv6 device. 571 * 572 * <p>To refresh this value use the {@link #readDeviceInfo()} method.</p> 573 * 574 * @return The IPv6 address of this IPv6 device. 575 * 576 * @see java.net.Inet6Address 577 * 578 * @since 1.2.1 579 */ 580 public Inet6Address getIPv6Address() { 581 return ipv6Address; 582 } 583 584 /** 585 * Returns the Operating mode (AT, API or API escaped) of this XBee device 586 * for a local device, and the operating mode of the local device used as 587 * communication interface for a remote device. 588 * 589 * @return The operating mode of the local XBee device. 590 * 591 * @see #isRemote() 592 * @see com.digi.xbee.api.models.OperatingMode 593 */ 594 protected OperatingMode getOperatingMode() { 595 if (isRemote()) 596 return localXBeeDevice.getOperatingMode(); 597 return operatingMode; 598 } 599 600 /** 601 * Returns the XBee Protocol of this XBee device. 602 * 603 * <p>To refresh this value use the {@link #readDeviceInfo()} method.</p> 604 * 605 * @return The XBee device protocol. 606 * 607 * @see com.digi.xbee.api.models.XBeeProtocol 608 */ 609 public XBeeProtocol getXBeeProtocol() { 610 return xbeeProtocol; 611 } 612 613 /** 614 * Returns the node identifier of this XBee device. 615 * 616 * <p>To refresh this value use the {@link #readDeviceInfo()} method.</p> 617 * 618 * @return The node identifier of this device. 619 * 620 * @see #setNodeID(String) 621 */ 622 public String getNodeID() { 623 return nodeID; 624 } 625 626 /** 627 * Sets the node identifier of this XBee device. 628 * 629 * @param nodeID The new node id of the device. 630 * 631 * @throws IllegalArgumentException if {@code nodeID.length > 20}. 632 * @throws InterfaceNotOpenException if this device connection is not open. 633 * @throws NullPointerException if {@code nodeID == null}. 634 * @throws TimeoutException if there is a timeout setting the node ID value. 635 * @throws XBeeException if there is any other XBee related exception. 636 * 637 * @see #getNodeID() 638 */ 639 public void setNodeID(String nodeID) throws TimeoutException, XBeeException { 640 if (nodeID == null) 641 throw new NullPointerException("Node ID cannot be null."); 642 if (nodeID.length() > 20) 643 throw new IllegalArgumentException("Node ID length must be less than 21."); 644 645 setParameter("NI", nodeID.getBytes()); 646 647 this.nodeID = nodeID; 648 } 649 650 /** 651 * Returns the firmware version (hexadecimal string value) of this XBee 652 * device. 653 * 654 * <p>To refresh this value use the {@link #readDeviceInfo()} method.</p> 655 * 656 * @return The firmware version of the XBee device. 657 */ 658 public String getFirmwareVersion() { 659 return firmwareVersion; 660 } 661 662 /** 663 * Returns the hardware version of this XBee device. 664 * 665 * <p>If this value is {@code null}, use the {@link #readDeviceInfo()} 666 * method to get its value.</p> 667 * 668 * @return The hardware version of the XBee device. 669 * 670 * @see com.digi.xbee.api.models.HardwareVersion 671 * @see com.digi.xbee.api.models.HardwareVersionEnum 672 */ 673 public HardwareVersion getHardwareVersion() { 674 return hardwareVersion; 675 } 676 677 /** 678 * Updates the current device reference with the data provided for the 679 * given device. 680 * 681 * <p><b>This is only for internal use.</b></p> 682 * 683 * @param device The XBee Device to get the data from. 684 */ 685 public void updateDeviceDataFrom(AbstractXBeeDevice device) { 686 // TODO Should the devices have the same protocol?? 687 // TODO Should be allow to update a local from a remote or viceversa?? Maybe 688 // this must be in the Local/Remote device class(es) and not here... 689 690 // Only update the Node Identifier if the provided is not null. 691 if (device.getNodeID() != null) 692 this.nodeID = device.getNodeID(); 693 694 // Only update the 64-bit address if the original is null or unknown. 695 XBee64BitAddress addr64 = device.get64BitAddress(); 696 if (addr64 != null && !addr64.equals(XBee64BitAddress.UNKNOWN_ADDRESS) 697 && !addr64.equals(xbee64BitAddress) 698 && (xbee64BitAddress == null 699 || xbee64BitAddress.equals(XBee64BitAddress.UNKNOWN_ADDRESS))) { 700 xbee64BitAddress = addr64; 701 } 702 703 // TODO Change here the 16-bit address or maybe in ZigBee and 802.15.4? 704 // TODO Should the 16-bit address be always updated? Or following the same rule as the 64-bit address. 705 XBee16BitAddress addr16 = device.get16BitAddress(); 706 if (addr16 != null && !addr16.equals(xbee16BitAddress)) { 707 xbee16BitAddress = addr16; 708 } 709 710 //this.deviceType = device.deviceType; // This is not yet done. 711 712 // The operating mode: only API/API2. Do we need this for a remote device? 713 // The protocol of the device should be the same. 714 // The hardware version should be the same. 715 // The firmware version can change... 716 } 717 718 /** 719 * Adds the provided listener to the list of listeners to be notified 720 * when new packets are received. 721 * 722 * <p>If the listener has been already included, this method does nothing. 723 * </p> 724 * 725 * @param listener Listener to be notified when new packets are received. 726 * 727 * @throws NullPointerException if {@code listener == null} 728 * 729 * @see #removePacketListener(IPacketReceiveListener) 730 * @see com.digi.xbee.api.listeners.IPacketReceiveListener 731 */ 732 protected void addPacketListener(IPacketReceiveListener listener) { 733 if (listener == null) 734 throw new NullPointerException("Listener cannot be null."); 735 736 if (dataReader == null) 737 return; 738 dataReader.addPacketReceiveListener(listener); 739 } 740 741 /** 742 * Removes the provided listener from the list of packets listeners. 743 * 744 * <p>If the listener was not in the list this method does nothing.</p> 745 * 746 * @param listener Listener to be removed from the list of listeners. 747 * 748 * @throws NullPointerException if {@code listener == null} 749 * 750 * @see #addPacketListener(IPacketReceiveListener) 751 * @see com.digi.xbee.api.listeners.IPacketReceiveListener 752 */ 753 protected void removePacketListener(IPacketReceiveListener listener) { 754 if (listener == null) 755 throw new NullPointerException("Listener cannot be null."); 756 757 if (dataReader == null) 758 return; 759 dataReader.removePacketReceiveListener(listener); 760 } 761 762 /** 763 * Adds the provided listener to the list of listeners to be notified 764 * when new data from a remote XBee device is received. 765 * 766 * <p>If the listener has been already included this method does nothing. 767 * </p> 768 * 769 * @param listener Listener to be notified when new data from a remote XBee 770 * device is received. 771 * 772 * @throws NullPointerException if {@code listener == null} 773 * 774 * @see #removeDataListener(IDataReceiveListener) 775 * @see com.digi.xbee.api.listeners.IDataReceiveListener 776 */ 777 protected void addDataListener(IDataReceiveListener listener) { 778 if (listener == null) 779 throw new NullPointerException("Listener cannot be null."); 780 781 if (dataReader == null) 782 return; 783 dataReader.addDataReceiveListener(listener); 784 } 785 786 /** 787 * Removes the provided listener from the list of data listeners for remote 788 * XBee devices. 789 * 790 * <p>If the listener was not in the list this method does nothing.</p> 791 * 792 * @param listener Listener to be removed from the list of listeners. 793 * 794 * @throws NullPointerException if {@code listener == null} 795 * 796 * @see #addDataListener(IDataReceiveListener) 797 * @see com.digi.xbee.api.listeners.IDataReceiveListener 798 */ 799 protected void removeDataListener(IDataReceiveListener listener) { 800 if (listener == null) 801 throw new NullPointerException("Listener cannot be null."); 802 803 if (dataReader == null) 804 return; 805 dataReader.removeDataReceiveListener(listener); 806 } 807 808 /** 809 * Adds the provided listener to the list of listeners to be notified 810 * when new IO samples are received. 811 * 812 * <p>If the listener has been already included this method does nothing. 813 * </p> 814 * 815 * @param listener Listener to be notified when new IO samples are received. 816 * 817 * @throws NullPointerException if {@code listener == null} 818 * 819 * @see #removeIOSampleListener(IIOSampleReceiveListener) 820 * @see com.digi.xbee.api.listeners.IIOSampleReceiveListener 821 */ 822 protected void addIOSampleListener(IIOSampleReceiveListener listener) { 823 if (listener == null) 824 throw new NullPointerException("Listener cannot be null."); 825 826 if (dataReader == null) 827 return; 828 dataReader.addIOSampleReceiveListener(listener); 829 } 830 831 /** 832 * Removes the provided listener from the list of IO samples listeners. 833 * 834 * <p>If the listener was not in the list this method does nothing.</p> 835 * 836 * @param listener Listener to be removed from the list of listeners. 837 * 838 * @throws NullPointerException if {@code listener == null} 839 * 840 * @see #addIOSampleListener(IIOSampleReceiveListener) 841 * @see com.digi.xbee.api.listeners.IIOSampleReceiveListener 842 */ 843 protected void removeIOSampleListener(IIOSampleReceiveListener listener) { 844 if (listener == null) 845 throw new NullPointerException("Listener cannot be null."); 846 847 if (dataReader == null) 848 return; 849 dataReader.removeIOSampleReceiveListener(listener); 850 } 851 852 /** 853 * Adds the provided listener to the list of listeners to be notified 854 * when new Modem Status events are received. 855 * 856 * <p>If the listener has been already included this method does nothing. 857 * </p> 858 * 859 * @param listener Listener to be notified when new Modem Status events are 860 * received. 861 * 862 * @throws NullPointerException if {@code listener == null} 863 * 864 * @see #removeModemStatusListener(IModemStatusReceiveListener) 865 * @see com.digi.xbee.api.listeners.IModemStatusReceiveListener 866 */ 867 protected void addModemStatusListener(IModemStatusReceiveListener listener) { 868 if (listener == null) 869 throw new NullPointerException("Listener cannot be null."); 870 871 if (dataReader == null) 872 return; 873 dataReader.addModemStatusReceiveListener(listener); 874 } 875 876 /** 877 * Removes the provided listener from the list of Modem Status listeners. 878 * 879 * <p>If the listener was not in the list this method does nothing.</p> 880 * 881 * @param listener Listener to be removed from the list of listeners. 882 * 883 * @throws NullPointerException if {@code listener == null} 884 * 885 * @see #addModemStatusListener(IModemStatusReceiveListener) 886 * @see com.digi.xbee.api.listeners.IModemStatusReceiveListener 887 */ 888 protected void removeModemStatusListener(IModemStatusReceiveListener listener) { 889 if (listener == null) 890 throw new NullPointerException("Listener cannot be null."); 891 892 if (dataReader == null) 893 return; 894 dataReader.removeModemStatusReceiveListener(listener); 895 } 896 897 /** 898 * Adds the provided listener to the list of listeners to be notified 899 * when new explicit data packets are received. 900 * 901 * <p>If the listener has been already included this method does nothing. 902 * </p> 903 * 904 * @param listener Listener to be notified when new explicit data packets 905 * are received. 906 * 907 * @throws NullPointerException if {@code listener == null} 908 * 909 * @see #removeExplicitDataListener(IExplicitDataReceiveListener) 910 * @see com.digi.xbee.api.listeners.IExplicitDataReceiveListener 911 */ 912 protected void addExplicitDataListener(IExplicitDataReceiveListener listener) { 913 if (listener == null) 914 throw new NullPointerException("Listener cannot be null."); 915 916 if (dataReader == null) 917 return; 918 dataReader.addExplicitDataReceiveListener(listener); 919 } 920 921 /** 922 * Removes the provided listener from the list of explicit data receive 923 * listeners. 924 * 925 * <p>If the listener was not in the list this method does nothing.</p> 926 * 927 * @param listener Listener to be removed from the list of listeners. 928 * 929 * @throws NullPointerException if {@code listener == null} 930 * 931 * @see #addExplicitDataListener(IExplicitDataReceiveListener) 932 * @see com.digi.xbee.api.listeners.IExplicitDataReceiveListener 933 */ 934 protected void removeExplicitDataListener(IExplicitDataReceiveListener listener) { 935 if (listener == null) 936 throw new NullPointerException("Listener cannot be null."); 937 938 if (dataReader == null) 939 return; 940 dataReader.removeExplicitDataReceiveListener(listener); 941 } 942 943 944 /** 945 * Adds the provided listener to the list of listeners to be notified 946 * when new IP data is received. 947 * 948 * <p>If the listener has been already included this method does nothing. 949 * </p> 950 * 951 * @param listener Listener to be notified when new IP data is 952 * received. 953 * 954 * @throws NullPointerException if {@code listener == null} 955 * 956 * @see #removeIPDataListener(IIPDataReceiveListener) 957 * @see com.digi.xbee.api.listeners.IIPDataReceiveListener 958 * 959 * @since 1.2.0 960 */ 961 protected void addIPDataListener(IIPDataReceiveListener listener) { 962 if (listener == null) 963 throw new NullPointerException("Listener cannot be null."); 964 965 if (dataReader == null) 966 return; 967 dataReader.addIPDataReceiveListener(listener); 968 } 969 970 /** 971 * Removes the provided listener from the list of IP data listeners. 972 * 973 * <p>If the listener was not in the list this method does nothing.</p> 974 * 975 * @param listener Listener to be removed from the list of listeners. 976 * 977 * @throws NullPointerException if {@code listener == null} 978 * 979 * @see #addIPDataListener(IIPDataReceiveListener) 980 * @see com.digi.xbee.api.listeners.IIPDataReceiveListener 981 * 982 * @since 1.2.0 983 */ 984 protected void removeIPDataListener(IIPDataReceiveListener listener) { 985 if (listener == null) 986 throw new NullPointerException("Listener cannot be null."); 987 988 if (dataReader == null) 989 return; 990 dataReader.removeIPDataReceiveListener(listener); 991 } 992 993 /** 994 * Adds the provided listener to the list of listeners to be notified 995 * when new SMS is received. 996 * 997 * <p>If the listener has been already included this method does nothing. 998 * </p> 999 * 1000 * @param listener Listener to be notified when new SMS is received. 1001 * 1002 * @throws NullPointerException if {@code listener == null} 1003 * 1004 * @see #removeSMSListener(ISMSReceiveListener) 1005 * @see com.digi.xbee.api.listeners.ISMSReceiveListener 1006 * 1007 * @since 1.2.0 1008 */ 1009 protected void addSMSListener(ISMSReceiveListener listener) { 1010 if (listener == null) 1011 throw new NullPointerException("Listener cannot be null."); 1012 1013 if (dataReader == null) 1014 return; 1015 dataReader.addSMSReceiveListener(listener); 1016 } 1017 1018 /** 1019 * Removes the provided listener from the list of SMS listeners. 1020 * 1021 * <p>If the listener was not in the list this method does nothing.</p> 1022 * 1023 * @param listener Listener to be removed from the list of listeners. 1024 * 1025 * @throws NullPointerException if {@code listener == null} 1026 * 1027 * @see #addSMSListener(ISMSReceiveListener) 1028 * @see com.digi.xbee.api.listeners.ISMSReceiveListener 1029 * 1030 * @since 1.2.0 1031 */ 1032 protected void removeSMSListener(ISMSReceiveListener listener) { 1033 if (listener == null) 1034 throw new NullPointerException("Listener cannot be null."); 1035 1036 if (dataReader == null) 1037 return; 1038 dataReader.removeSMSReceiveListener(listener); 1039 } 1040 1041 /** 1042 * Adds the provided listener to the list of listeners to be notified 1043 * when new User Data Relay message is received. 1044 * 1045 * <p>If the listener has been already included this method does nothing. 1046 * </p> 1047 * 1048 * @param listener Listener to be notified when new User Data Relay message 1049 * is received. 1050 * 1051 * @throws NullPointerException if {@code listener == null} 1052 * 1053 * @see #removeUserDataRelayListener(IUserDataRelayReceiveListener) 1054 * @see IUserDataRelayReceiveListener 1055 * 1056 * @since 1.3.0 1057 */ 1058 protected void addUserDataRelayListener(IUserDataRelayReceiveListener listener) { 1059 if (listener == null) 1060 throw new NullPointerException("Listener cannot be null."); 1061 1062 if (dataReader == null) 1063 return; 1064 dataReader.addUserDataRelayReceiveListener(listener); 1065 } 1066 1067 /** 1068 * Removes the provided listener from the list of User Data Relay listeners. 1069 * 1070 * <p>If the listener was not in the list this method does nothing.</p> 1071 * 1072 * @param listener Listener to be removed from the list of listeners. 1073 * 1074 * @throws NullPointerException if {@code listener == null} 1075 * 1076 * @see #addUserDataRelayListener(IUserDataRelayReceiveListener) 1077 * @see IUserDataRelayReceiveListener 1078 * 1079 * @since 1.3.0 1080 */ 1081 protected void removeUserDataRelayListener(IUserDataRelayReceiveListener listener) { 1082 if (listener == null) 1083 throw new NullPointerException("Listener cannot be null."); 1084 1085 if (dataReader == null) 1086 return; 1087 dataReader.removeUserDataRelayReceiveListener(listener); 1088 } 1089 1090 /** 1091 * Adds the provided listener to the list of listeners to be notified 1092 * when new data from the Bluetooth interface is received in a User Data 1093 * Relay frame. 1094 * 1095 * <p>If the listener has been already included this method does nothing. 1096 * </p> 1097 * 1098 * @param listener Listener to be notified when new data from the Bluetooth 1099 * interface is received. 1100 * 1101 * @throws NullPointerException if {@code listener == null} 1102 * 1103 * @see #removeBluetoothDataListener(IBluetoothDataReceiveListener) 1104 * @see IBluetoothDataReceiveListener 1105 * 1106 * @since 1.3.0 1107 */ 1108 protected void addBluetoothDataListener(IBluetoothDataReceiveListener listener) { 1109 if (listener == null) 1110 throw new NullPointerException("Listener cannot be null."); 1111 1112 if (dataReader == null) 1113 return; 1114 dataReader.addBluetoothDataReceiveListener(listener); 1115 } 1116 1117 /** 1118 * Removes the provided listener from the list of data receive listeners 1119 * for the Bluetooth interface. 1120 * 1121 * <p>If the listener was not in the list this method does nothing.</p> 1122 * 1123 * @param listener Listener to be removed from the list of listeners. 1124 * 1125 * @throws NullPointerException if {@code listener == null} 1126 * 1127 * @see #addBluetoothDataListener(IBluetoothDataReceiveListener) 1128 * @see IBluetoothDataReceiveListener 1129 * 1130 * @since 1.3.0 1131 */ 1132 protected void removeBluetoothDataListener(IBluetoothDataReceiveListener listener) { 1133 if (listener == null) 1134 throw new NullPointerException("Listener cannot be null."); 1135 1136 if (dataReader == null) 1137 return; 1138 dataReader.removeBluetoothDataReceiveListener(listener); 1139 } 1140 1141 /** 1142 * Adds the provided listener to the list of listeners to be notified 1143 * when new data from the MicroPython interface is received in a User 1144 * Data Relay frame. 1145 * 1146 * <p>If the listener has been already included this method does nothing. 1147 * </p> 1148 * 1149 * @param listener Listener to be notified when new data from the 1150 * MicroPython interface is received. 1151 * 1152 * @throws NullPointerException if {@code listener == null} 1153 * 1154 * @see #removeMicroPythonDataListener(IMicroPythonDataReceiveListener) 1155 * @see IMicroPythonDataReceiveListener 1156 * 1157 * @since 1.3.0 1158 */ 1159 protected void addMicroPythonDataListener(IMicroPythonDataReceiveListener listener) { 1160 if (listener == null) 1161 throw new NullPointerException("Listener cannot be null."); 1162 1163 if (dataReader == null) 1164 return; 1165 dataReader.addMicroPythonDataReceiveListener(listener); 1166 } 1167 1168 /** 1169 * Removes the provided listener from the list of data receive listeners 1170 * for the MicroPython interface. 1171 * 1172 * <p>If the listener was not in the list this method does nothing.</p> 1173 * 1174 * @param listener Listener to be removed from the list of listeners. 1175 * 1176 * @throws NullPointerException if {@code listener == null} 1177 * 1178 * @see #addMicroPythonDataListener(IMicroPythonDataReceiveListener) 1179 * @see IMicroPythonDataReceiveListener 1180 * 1181 * @since 1.3.0 1182 */ 1183 protected void removeMicroPythonDataListener(IMicroPythonDataReceiveListener listener) { 1184 if (listener == null) 1185 throw new NullPointerException("Listener cannot be null."); 1186 1187 if (dataReader == null) 1188 return; 1189 dataReader.removeMicroPythonDataReceiveListener(listener); 1190 } 1191 1192 /** 1193 * Adds the provided listener to the list of listeners to be notified 1194 * when new data from the serial interface is received in a User Data 1195 * Relay frame. 1196 * 1197 * <p>If the listener has been already included this method does nothing. 1198 * </p> 1199 * 1200 * @param listener Listener to be notified when new data from the serial 1201 * interface is received. 1202 * 1203 * @throws NullPointerException if {@code listener == null} 1204 * 1205 * @see #removeSerialDataListener(ISerialDataReceiveListener) 1206 * @see ISerialDataReceiveListener 1207 * 1208 * @since 1.3.0 1209 */ 1210 protected void addSerialDataListener(ISerialDataReceiveListener listener) { 1211 if (listener == null) 1212 throw new NullPointerException("Listener cannot be null."); 1213 1214 if (dataReader == null) 1215 return; 1216 dataReader.addSerialDataReceiveListener(listener); 1217 } 1218 1219 /** 1220 * Removes the provided listener from the list of data receive listeners 1221 * for the serial interface. 1222 * 1223 * <p>If the listener was not in the list this method does nothing.</p> 1224 * 1225 * @param listener Listener to be removed from the list of listeners. 1226 * 1227 * @throws NullPointerException if {@code listener == null} 1228 * 1229 * @see #addSerialDataListener(ISerialDataReceiveListener) 1230 * @see ISerialDataReceiveListener 1231 * 1232 * @since 1.3.0 1233 */ 1234 protected void removeSerialDataListener(ISerialDataReceiveListener listener) { 1235 if (listener == null) 1236 throw new NullPointerException("Listener cannot be null."); 1237 1238 if (dataReader == null) 1239 return; 1240 dataReader.removeSerialDataReceiveListener(listener); 1241 } 1242 1243 /** 1244 * Sends the given AT command and waits for answer or until the configured 1245 * receive timeout expires. 1246 * 1247 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 1248 * method and can be consulted with {@code getReceiveTimeout} method.</p> 1249 * 1250 * @param command AT command to be sent. 1251 * @return An {@code ATCommandResponse} object containing the response of 1252 * the command or {@code null} if there is no response. 1253 * 1254 * @throws InterfaceNotOpenException if this device connection is not open. 1255 * @throws InvalidOperatingModeException if the operating mode is different 1256 * than {@link OperatingMode#API} and 1257 * {@link OperatingMode#API_ESCAPE}. 1258 * @throws IOException if an I/O error occurs while sending the AT command. 1259 * @throws NullPointerException if {@code command == null}. 1260 * @throws TimeoutException if the configured time expires while waiting 1261 * for the command reply. 1262 * 1263 * @see XBeeDevice#getReceiveTimeout() 1264 * @see XBeeDevice#setReceiveTimeout(int) 1265 * @see com.digi.xbee.api.models.ATCommand 1266 * @see com.digi.xbee.api.models.ATCommandResponse 1267 */ 1268 protected ATCommandResponse sendATCommand(ATCommand command) 1269 throws InvalidOperatingModeException, TimeoutException, IOException { 1270 // Check if command is null. 1271 if (command == null) 1272 throw new NullPointerException("AT command cannot be null."); 1273 // Check connection. 1274 if (!connectionInterface.isOpen()) 1275 throw new InterfaceNotOpenException(); 1276 1277 ATCommandResponse response = null; 1278 OperatingMode operatingMode = getOperatingMode(); 1279 switch (operatingMode) { 1280 case AT: 1281 case UNKNOWN: 1282 default: 1283 throw new InvalidOperatingModeException(operatingMode); 1284 case API: 1285 case API_ESCAPE: 1286 // Create the corresponding AT command packet depending on if the device is local or remote. 1287 XBeePacket packet; 1288 if (isRemote()) { 1289 int remoteATCommandOptions = RemoteATCommandOptions.OPTION_NONE; 1290 if (isApplyConfigurationChangesEnabled()) 1291 remoteATCommandOptions |= RemoteATCommandOptions.OPTION_APPLY_CHANGES; 1292 1293 if (getXBeeProtocol() == XBeeProtocol.THREAD) { 1294 packet = new IPv6RemoteATCommandRequestPacket(getNextFrameID(), ipv6Address, 1295 remoteATCommandOptions, command.getCommand(), command.getParameter()); 1296 } else{ 1297 XBee16BitAddress remote16BitAddress = get16BitAddress(); 1298 if (remote16BitAddress == null) 1299 remote16BitAddress = XBee16BitAddress.UNKNOWN_ADDRESS; 1300 1301 packet = new RemoteATCommandPacket(getNextFrameID(), get64BitAddress(), 1302 remote16BitAddress, remoteATCommandOptions, command.getCommand(), command.getParameter()); 1303 } 1304 } else { 1305 if (isApplyConfigurationChangesEnabled()) 1306 packet = new ATCommandPacket(getNextFrameID(), command.getCommand(), command.getParameter()); 1307 else 1308 packet = new ATCommandQueuePacket(getNextFrameID(), command.getCommand(), command.getParameter()); 1309 } 1310 if (command.getParameter() == null) 1311 logger.debug(toString() + "Sending AT command '{}'.", command.getCommand()); 1312 else 1313 logger.debug(toString() + "Sending AT command '{} {}'.", command.getCommand(), 1314 HexUtils.prettyHexString(command.getParameter())); 1315 try { 1316 // Send the packet and build the corresponding response depending on if the device is local or remote. 1317 XBeePacket answerPacket; 1318 if (isRemote()) 1319 answerPacket = localXBeeDevice.sendXBeePacket(packet); 1320 else 1321 answerPacket = sendXBeePacket(packet); 1322 1323 if (answerPacket instanceof ATCommandResponsePacket) { 1324 ATCommandResponsePacket r = (ATCommandResponsePacket)answerPacket; 1325 response = new ATCommandResponse(command, r.getCommandValue(), r.getStatus()); 1326 } else if (answerPacket instanceof RemoteATCommandResponsePacket) { 1327 RemoteATCommandResponsePacket r = (RemoteATCommandResponsePacket)answerPacket; 1328 response = new ATCommandResponse(command, r.getCommandValue(), r.getStatus()); 1329 } else if (answerPacket instanceof IPv6RemoteATCommandResponsePacket) { 1330 IPv6RemoteATCommandResponsePacket r = (IPv6RemoteATCommandResponsePacket)answerPacket; 1331 response = new ATCommandResponse(command, r.getCommandValue(), r.getStatus()); 1332 } 1333 1334 if (response != null && response.getResponse() != null) 1335 logger.debug(toString() + "AT command response: {}.", HexUtils.prettyHexString(response.getResponse())); 1336 else 1337 logger.debug(toString() + "AT command response: null."); 1338 } catch (ClassCastException e) { 1339 logger.error("Received an invalid packet type after sending an AT command packet." + e); 1340 } 1341 } 1342 return response; 1343 } 1344 1345 /** 1346 * Sends the given XBee packet asynchronously. 1347 * 1348 * <p>The method will not wait for an answer for the packet.</p> 1349 * 1350 * <p>To be notified when the answer is received, use 1351 * {@link #sendXBeePacket(XBeePacket, IPacketReceiveListener)}.</p> 1352 * 1353 * @param packet XBee packet to be sent asynchronously. 1354 * 1355 * @throws InterfaceNotOpenException if this device connection is not open. 1356 * @throws InvalidOperatingModeException if the operating mode is different 1357 * than {@link OperatingMode#API} and 1358 * {@link OperatingMode#API_ESCAPE}. 1359 * @throws IOException if an I/O error occurs while sending the XBee packet. 1360 * @throws NullPointerException if {@code packet == null}. 1361 * 1362 * @see #sendXBeePacket(XBeePacket) 1363 * @see #sendXBeePacket(XBeePacket, IPacketReceiveListener) 1364 * @see #sendXBeePacketAsync(XBeePacket) 1365 * @see com.digi.xbee.api.packet.XBeePacket 1366 */ 1367 protected void sendXBeePacketAsync(XBeePacket packet) 1368 throws InvalidOperatingModeException, IOException { 1369 sendXBeePacket(packet, null); 1370 } 1371 1372 /** 1373 * Sends the given XBee packet asynchronously and registers the given 1374 * packet listener (if not {@code null}) to wait for an answer. 1375 * 1376 * <p>The method will not wait for an answer for the packet, but the given 1377 * listener will be notified when the answer arrives.</p> 1378 * 1379 * @param packet XBee packet to be sent. 1380 * @param packetReceiveListener Listener for the operation, {@code null} 1381 * not to be notified when the answer arrives. 1382 * 1383 * @throws InterfaceNotOpenException if this device connection is not open. 1384 * @throws InvalidOperatingModeException if the operating mode is different 1385 * than {@link OperatingMode#API} and 1386 * {@link OperatingMode#API_ESCAPE}. 1387 * @throws IOException if an I/O error occurs while sending the XBee packet. 1388 * @throws NullPointerException if {@code packet == null}. 1389 * 1390 * @see #sendXBeePacket(XBeePacket) 1391 * @see #sendXBeePacket(XBeePacket, IPacketReceiveListener) 1392 * @see #sendXBeePacketAsync(XBeePacket) 1393 * @see com.digi.xbee.api.listeners.IPacketReceiveListener 1394 * @see com.digi.xbee.api.packet.XBeePacket 1395 */ 1396 protected void sendXBeePacket(XBeePacket packet, IPacketReceiveListener packetReceiveListener) 1397 throws InvalidOperatingModeException, IOException { 1398 // Check if the packet to send is null. 1399 if (packet == null) 1400 throw new NullPointerException("XBee packet cannot be null."); 1401 // Check connection. 1402 if (!connectionInterface.isOpen()) 1403 throw new InterfaceNotOpenException(); 1404 1405 OperatingMode operatingMode = getOperatingMode(); 1406 switch (operatingMode) { 1407 case AT: 1408 case UNKNOWN: 1409 default: 1410 throw new InvalidOperatingModeException(operatingMode); 1411 case API: 1412 case API_ESCAPE: 1413 // Add the required frame ID and subscribe listener if given. 1414 if (packet instanceof XBeeAPIPacket) { 1415 1416 insertFrameID(packet); 1417 1418 XBeeAPIPacket apiPacket = (XBeeAPIPacket)packet; 1419 1420 if (packetReceiveListener != null 1421 && apiPacket.needsAPIFrameID()) 1422 dataReader.addPacketReceiveListener(packetReceiveListener, apiPacket.getFrameID()); 1423 else if (packetReceiveListener != null) 1424 dataReader.addPacketReceiveListener(packetReceiveListener); 1425 } 1426 1427 // Write packet data. 1428 writePacket(packet); 1429 break; 1430 } 1431 } 1432 1433 /** 1434 * Sends the given XBee packet synchronously and blocks until response is 1435 * received or receive timeout is reached. 1436 * 1437 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 1438 * method and can be consulted with {@code getReceiveTimeout} method.</p> 1439 * 1440 * <p>Use {@link #sendXBeePacketAsync(XBeePacket)} for non-blocking 1441 * operations.</p> 1442 * 1443 * @param packet XBee packet to be sent. 1444 * @return An {@code XBeePacket} containing the response of the sent packet 1445 * or {@code null} if there is no response. 1446 * 1447 * @throws InterfaceNotOpenException if this device connection is not open. 1448 * @throws InvalidOperatingModeException if the operating mode is different 1449 * than {@link OperatingMode#API} and 1450 * {@link OperatingMode#API_ESCAPE}. 1451 * @throws IOException if an I/O error occurs while sending the XBee packet. 1452 * @throws NullPointerException if {@code packet == null}. 1453 * @throws TimeoutException if the configured time expires while waiting for 1454 * the packet reply. 1455 * 1456 * @see #sendXBeePacket(XBeePacket) 1457 * @see #sendXBeePacket(XBeePacket, IPacketReceiveListener) 1458 * @see #sendXBeePacketAsync(XBeePacket) 1459 * @see XBeeDevice#setReceiveTimeout(int) 1460 * @see XBeeDevice#getReceiveTimeout() 1461 * @see com.digi.xbee.api.packet.XBeePacket 1462 */ 1463 protected XBeePacket sendXBeePacket(final XBeePacket packet) 1464 throws InvalidOperatingModeException, TimeoutException, IOException { 1465 // Check if the packet to send is null. 1466 if (packet == null) 1467 throw new NullPointerException("XBee packet cannot be null."); 1468 // Check connection. 1469 if (!connectionInterface.isOpen()) 1470 throw new InterfaceNotOpenException(); 1471 1472 OperatingMode operatingMode = getOperatingMode(); 1473 switch (operatingMode) { 1474 case AT: 1475 case UNKNOWN: 1476 default: 1477 throw new InvalidOperatingModeException(operatingMode); 1478 case API: 1479 case API_ESCAPE: 1480 // Build response container. 1481 ArrayList<XBeePacket> responseList = new ArrayList<XBeePacket>(); 1482 1483 // If the packet does not need frame ID, send it async. and return null. 1484 if (packet instanceof XBeeAPIPacket) { 1485 if (!((XBeeAPIPacket)packet).needsAPIFrameID()) { 1486 sendXBeePacketAsync(packet); 1487 return null; 1488 } 1489 } else { 1490 sendXBeePacketAsync(packet); 1491 return null; 1492 } 1493 1494 // Add the required frame ID to the packet if necessary. 1495 insertFrameID(packet); 1496 1497 // Generate a packet received listener for the packet to be sent. 1498 IPacketReceiveListener packetReceiveListener = createPacketReceivedListener(packet, responseList); 1499 1500 // Add the packet listener to the data reader. 1501 addPacketListener(packetReceiveListener); 1502 1503 // Write the packet data. 1504 writePacket(packet); 1505 try { 1506 // Wait for response or timeout. 1507 synchronized (responseList) { 1508 try { 1509 responseList.wait(receiveTimeout); 1510 } catch (InterruptedException e) {} 1511 } 1512 // After the wait check if we received any response, if not throw timeout exception. 1513 if (responseList.size() < 1) 1514 throw new TimeoutException(); 1515 // Return the received packet. 1516 return responseList.get(0); 1517 } finally { 1518 // Always remove the packet listener from the list. 1519 removePacketListener(packetReceiveListener); 1520 } 1521 } 1522 } 1523 1524 /** 1525 * Insert (if possible) the next frame ID stored in the device to the 1526 * provided packet. 1527 * 1528 * @param xbeePacket The packet to add the frame ID. 1529 * 1530 * @see com.digi.xbee.api.packet.XBeePacket 1531 */ 1532 private void insertFrameID(XBeePacket xbeePacket) { 1533 if (xbeePacket instanceof XBeeAPIPacket) 1534 return; 1535 1536 XBeeAPIPacket apiPacket = (XBeeAPIPacket)xbeePacket; 1537 if (apiPacket.needsAPIFrameID() 1538 && apiPacket.getFrameID() == XBeeAPIPacket.NO_FRAME_ID) 1539 apiPacket.setFrameID(getNextFrameID()); 1540 } 1541 1542 /** 1543 * Returns the packet listener corresponding to the provided sent packet. 1544 * 1545 * <p>The listener will filter those packets matching with the Frame ID of 1546 * the sent packet storing them in the provided responseList array.</p> 1547 * 1548 * @param sentPacket The packet sent. 1549 * @param responseList List of packets received that correspond to the 1550 * frame ID of the packet sent. 1551 * 1552 * @return A packet receive listener that will filter the packets received 1553 * corresponding to the sent one. 1554 * 1555 * @see com.digi.xbee.api.listeners.IPacketReceiveListener 1556 * @see com.digi.xbee.api.packet.XBeePacket 1557 */ 1558 private IPacketReceiveListener createPacketReceivedListener(final XBeePacket sentPacket, final ArrayList<XBeePacket> responseList) { 1559 IPacketReceiveListener packetReceiveListener = new IPacketReceiveListener() { 1560 /* 1561 * (non-Javadoc) 1562 * @see com.digi.xbee.api.listeners.IPacketReceiveListener#packetReceived(com.digi.xbee.api.packet.XBeePacket) 1563 */ 1564 @Override 1565 public void packetReceived(XBeePacket receivedPacket) { 1566 // Check if it is the packet we are waiting for. 1567 if (((XBeeAPIPacket)receivedPacket).checkFrameID((((XBeeAPIPacket)sentPacket).getFrameID()))) { 1568 // Security check to avoid class cast exceptions. It has been observed that parallel processes 1569 // using the same connection but with different frame index may collide and cause this exception at some point. 1570 if (sentPacket instanceof XBeeAPIPacket 1571 && receivedPacket instanceof XBeeAPIPacket) { 1572 XBeeAPIPacket sentAPIPacket = (XBeeAPIPacket)sentPacket; 1573 XBeeAPIPacket receivedAPIPacket = (XBeeAPIPacket)receivedPacket; 1574 1575 // If the packet sent is an AT command, verify that the received one is an AT command response and 1576 // the command matches in both packets. 1577 if (sentAPIPacket.getFrameType() == APIFrameType.AT_COMMAND) { 1578 if (receivedAPIPacket.getFrameType() != APIFrameType.AT_COMMAND_RESPONSE) 1579 return; 1580 if (!((ATCommandPacket)sentAPIPacket).getCommand().equalsIgnoreCase(((ATCommandResponsePacket)receivedPacket).getCommand())) 1581 return; 1582 } 1583 // If the packet sent is a remote AT command, verify that the received one is a remote AT command response and 1584 // the command matches in both packets. 1585 if (sentAPIPacket.getFrameType() == APIFrameType.REMOTE_AT_COMMAND_REQUEST) { 1586 if (receivedAPIPacket.getFrameType() != APIFrameType.REMOTE_AT_COMMAND_RESPONSE) 1587 return; 1588 if (!((RemoteATCommandPacket)sentAPIPacket).getCommand().equalsIgnoreCase(((RemoteATCommandResponsePacket)receivedPacket).getCommand())) 1589 return; 1590 } 1591 } 1592 1593 // Verify that the sent packet is not the received one! This can happen when the echo mode is enabled in the 1594 // serial port. 1595 if (!sentPacket.equals(receivedPacket)) { 1596 responseList.add(receivedPacket); 1597 synchronized (responseList) { 1598 responseList.notify(); 1599 } 1600 } 1601 } 1602 } 1603 }; 1604 1605 return packetReceiveListener; 1606 } 1607 1608 /** 1609 * Writes the given XBee packet in the connection interface of this device. 1610 * 1611 * @param packet XBee packet to be written. 1612 * 1613 * @throws IOException if an I/O error occurs while writing the XBee packet 1614 * in the connection interface. 1615 * 1616 * @see com.digi.xbee.api.packet.XBeePacket 1617 */ 1618 private void writePacket(XBeePacket packet) throws IOException { 1619 logger.debug(toString() + "Sending XBee packet: \n{}", packet.toPrettyString()); 1620 // Write bytes with the required escaping mode. 1621 switch (getOperatingMode()) { 1622 case API: 1623 default: 1624 connectionInterface.writeData(packet.generateByteArray()); 1625 break; 1626 case API_ESCAPE: 1627 connectionInterface.writeData(packet.generateByteArrayEscaped()); 1628 break; 1629 } 1630 } 1631 1632 /** 1633 * Returns the next Frame ID of this XBee device. 1634 * 1635 * @return The next Frame ID. 1636 */ 1637 protected synchronized int getNextFrameID() { 1638 if (isRemote()) 1639 return localXBeeDevice.getNextFrameID(); 1640 if (currentFrameID == 0xff) { 1641 // Reset counter. 1642 currentFrameID = 1; 1643 } else 1644 currentFrameID ++; 1645 return currentFrameID; 1646 } 1647 1648 /** 1649 * Sends the provided {@code XBeePacket} and determines if the transmission 1650 * status is success for synchronous transmissions. 1651 * 1652 * <p>If the status is not success, an {@code TransmitException} is thrown.</p> 1653 * 1654 * @param packet The {@code XBeePacket} to be sent. 1655 * @param asyncTransmission Determines whether the transmission must be 1656 * asynchronous. 1657 * 1658 * @throws InterfaceNotOpenException if this device connection is not open. 1659 * @throws NullPointerException if {@code packet == null}. 1660 * @throws TransmitException if {@code packet} is not an instance of 1661 * {@code TransmitStatusPacket} or 1662 * if {@code packet} is not an instance of 1663 * {@code TXStatusPacket} or 1664 * if its transmit status is different than 1665 * {@code XBeeTransmitStatus.SUCCESS}. 1666 * @throws XBeeException if there is any other XBee related error. 1667 * 1668 * @see com.digi.xbee.api.packet.XBeePacket 1669 */ 1670 protected void sendAndCheckXBeePacket(XBeePacket packet, boolean asyncTransmission) throws TransmitException, XBeeException { 1671 XBeePacket receivedPacket = null; 1672 1673 // Send the XBee packet. 1674 try { 1675 if (asyncTransmission) 1676 sendXBeePacketAsync(packet); 1677 else 1678 receivedPacket = sendXBeePacket(packet); 1679 } catch (IOException e) { 1680 throw new XBeeException("Error writing in the communication interface.", e); 1681 } 1682 1683 // If the transmission is async. we are done. 1684 if (asyncTransmission) 1685 return; 1686 1687 // Check if the packet received is a valid transmit status packet. 1688 if (receivedPacket == null) 1689 throw new TransmitException(null); 1690 1691 XBeeTransmitStatus status = null; 1692 if (receivedPacket instanceof TransmitStatusPacket) 1693 status = ((TransmitStatusPacket)receivedPacket).getTransmitStatus(); 1694 else if (receivedPacket instanceof TXStatusPacket) 1695 status = ((TXStatusPacket)receivedPacket).getTransmitStatus(); 1696 1697 if (status != XBeeTransmitStatus.SUCCESS 1698 && status != XBeeTransmitStatus.SELF_ADDRESSED) 1699 throw new TransmitException(status); 1700 } 1701 1702 /** 1703 * Sends the provided {@code CoAPTxRequestPacket} and determines if the 1704 * transmission status and CoAP RX Response are success for synchronous 1705 * transmissions. 1706 * 1707 * <p>If the status or the CoAP response is not successful, an 1708 * {@code TransmitException} is thrown.</p> 1709 * 1710 * @param packet The {@code CoAPTxRequestPacket} to be sent. 1711 * @param asyncTransmission Determines whether the transmission must be 1712 * asynchronous. 1713 * 1714 * @return A byte array containing the RfData of the CoAP RX Response 1715 * packet, if that field is not empty. In other cases, it will 1716 * return {@code null}. 1717 * 1718 * @throws InterfaceNotOpenException if this device connection is not open. 1719 * @throws NullPointerException if {@code packet == null}. 1720 * @throws TransmitException if {@code packet} is not an instance of 1721 * {@code TransmitStatusPacket} or 1722 * if {@code packet} is not an instance of 1723 * {@code TXStatusPacket} or 1724 * if its transmit status is different than 1725 * {@code XBeeTransmitStatus.SUCCESS}. 1726 * @throws XBeeException if CoAP response packet is not received or it is 1727 * not successful or if there is any other XBee 1728 * related error. 1729 * 1730 * @see com.digi.xbee.api.packet.thread.CoAPTxRequestPacket 1731 * 1732 * @since 1.2.1 1733 */ 1734 protected byte[] sendAndCheckCoAPPacket(CoAPTxRequestPacket packet, 1735 boolean asyncTransmission) throws TransmitException, XBeeException { 1736 // Add listener to read CoAP response (when sending a CoAP transmission, 1737 // a transmit status and a CoAP response are received by the sender) 1738 ArrayList<CoAPRxResponsePacket> coapResponsePackets = new ArrayList<CoAPRxResponsePacket>(); 1739 IPacketReceiveListener listener = createCoAPResponseListener(coapResponsePackets); 1740 addPacketListener(listener); 1741 1742 // Send the CoAP Tx Request packet. 1743 XBeePacket receivedPacket = null; 1744 try { 1745 if (asyncTransmission) 1746 sendXBeePacketAsync(packet); 1747 else 1748 receivedPacket = sendXBeePacket(packet); 1749 } catch (IOException e) { 1750 throw new XBeeException("Error writing in the communication interface.", e); 1751 } 1752 1753 // If the transmission is async. we are done. 1754 if (asyncTransmission) 1755 return null; 1756 1757 if (receivedPacket == null) 1758 throw new TransmitException(null); 1759 1760 // Verify Transmit status. 1761 XBeeTransmitStatus status = null; 1762 if (receivedPacket instanceof TXStatusPacket) 1763 status = ((TXStatusPacket)receivedPacket).getTransmitStatus(); 1764 1765 if (status == null || 1766 (status != XBeeTransmitStatus.SUCCESS && status != XBeeTransmitStatus.SELF_ADDRESSED)) 1767 throw new TransmitException(status); 1768 1769 // Verify CoAP response (only expect one CoAP RX Response packet). 1770 CoAPRxResponsePacket coapRxPacket = null; 1771 try { 1772 coapRxPacket = waitForCoAPRxResponsePacket(coapResponsePackets); 1773 } finally { 1774 // Always remove the packet listener from the list. 1775 removePacketListener(listener); 1776 } 1777 if (coapRxPacket == null) 1778 throw new XBeeException("CoAP response was null."); 1779 return coapRxPacket.getData(); 1780 } 1781 1782 /** 1783 * Returns the CoAP packet listener corresponding to the provided sent CoAP 1784 * packet. 1785 * 1786 * <p>The listener will filter CoAP Rx Response packets (0x9C) and storing 1787 * them in the provided responseList array.</p> 1788 * 1789 * @param coapResponsePackets List of CoAP Rx Response packets received. 1790 * 1791 * @return A CoAP packet receive listener. 1792 * 1793 * @see com.digi.xbee.api.listeners.IPacketReceiveListener 1794 * @see com.digi.xbee.api.packet.thread.CoAPRxResponsePacket 1795 * 1796 * @since 1.2.1 1797 */ 1798 private IPacketReceiveListener createCoAPResponseListener(final ArrayList<CoAPRxResponsePacket> coapResponsePackets) { 1799 IPacketReceiveListener listener = new IPacketReceiveListener() { 1800 1801 @Override 1802 public void packetReceived(XBeePacket receivedPacket) { 1803 if (receivedPacket instanceof CoAPRxResponsePacket) { 1804 coapResponsePackets.add((CoAPRxResponsePacket)receivedPacket); 1805 coapResponsePackets.notifyAll(); 1806 } 1807 } 1808 }; 1809 return listener; 1810 } 1811 1812 /** 1813 * Returns the CoAP Rx Response packet that comes in through the serial 1814 * port in the given timeout. 1815 * 1816 * @param coapResponsePackets List of packets where the received packet will be stored. 1817 * 1818 * @return CoAP Rx Response packet received. 1819 * 1820 * @throws XBeeException if CoAP response packet is not received or it is 1821 * not successful or if there is any other XBee 1822 * related error. 1823 * 1824 * @since 1.2.1 1825 */ 1826 private CoAPRxResponsePacket waitForCoAPRxResponsePacket(ArrayList<CoAPRxResponsePacket> coapResponsePackets) throws XBeeException { 1827 synchronized (coapResponsePackets) { 1828 try { 1829 coapResponsePackets.wait(receiveTimeout); 1830 } catch (InterruptedException e) {} 1831 } 1832 1833 if (!coapResponsePackets.isEmpty()) { 1834 RestFulStatusEnum responseStatus = coapResponsePackets.get(0).getStatus(); 1835 if (responseStatus != RestFulStatusEnum.SUCCESS 1836 && responseStatus != RestFulStatusEnum.CREATED 1837 && responseStatus != RestFulStatusEnum.ACCEPTED 1838 && responseStatus != RestFulStatusEnum.NON_AUTHORITATIVE 1839 && responseStatus != RestFulStatusEnum.NO_CONTENT 1840 && responseStatus != RestFulStatusEnum.RESET_CONTENT) 1841 throw new XBeeException("CoAP response had an unexpected status: " + responseStatus.toString()); 1842 } else { 1843 throw new XBeeException("CoAP response was not received."); 1844 } 1845 return coapResponsePackets.get(0); 1846 } 1847 1848 /** 1849 * Sets the configuration of the given IO line of this XBee device. 1850 * 1851 * @param ioLine The IO line to configure. 1852 * @param ioMode The IO mode to set to the IO line. 1853 * 1854 * @throws InterfaceNotOpenException if this device connection is not open. 1855 * @throws NullPointerException if {@code ioLine == null} or 1856 * if {@code ioMode == null}. 1857 * @throws TimeoutException if there is a timeout sending the set 1858 * configuration command. 1859 * @throws XBeeException if there is any other XBee related exception. 1860 * 1861 * @see #getIOConfiguration(IOLine) 1862 * @see com.digi.xbee.api.io.IOLine 1863 * @see com.digi.xbee.api.io.IOMode 1864 */ 1865 public void setIOConfiguration(IOLine ioLine, IOMode ioMode) throws TimeoutException, XBeeException { 1866 // Check IO line. 1867 if (ioLine == null) 1868 throw new NullPointerException("IO line cannot be null."); 1869 if (ioMode == null) 1870 throw new NullPointerException("IO mode cannot be null."); 1871 // Check connection. 1872 if (!connectionInterface.isOpen()) 1873 throw new InterfaceNotOpenException(); 1874 1875 setParameter(ioLine.getConfigurationATCommand(), new byte[]{(byte)ioMode.getID()}); 1876 } 1877 1878 /** 1879 * Returns the configuration mode of the provided IO line of this XBee 1880 * device. 1881 * 1882 * @param ioLine The IO line to get its configuration. 1883 * 1884 * @return The IO mode (configuration) of the provided IO line. 1885 * 1886 * @throws InterfaceNotOpenException if this device connection is not open. 1887 * @throws NullPointerException if {@code ioLine == null}. 1888 * @throws TimeoutException if there is a timeout sending the get 1889 * configuration command. 1890 * @throws XBeeException if there is any other XBee related exception. 1891 * 1892 * @see #setIOConfiguration(IOLine, IOMode) 1893 * @see com.digi.xbee.api.io.IOLine 1894 * @see com.digi.xbee.api.io.IOMode 1895 */ 1896 public IOMode getIOConfiguration(IOLine ioLine) throws TimeoutException, XBeeException { 1897 // Check IO line. 1898 if (ioLine == null) 1899 throw new NullPointerException("DIO pin cannot be null."); 1900 // Check connection. 1901 if (!connectionInterface.isOpen()) 1902 throw new InterfaceNotOpenException(); 1903 1904 // Check if the received configuration mode is valid. 1905 int ioModeValue = getParameter(ioLine.getConfigurationATCommand())[0]; 1906 IOMode dioMode = IOMode.getIOMode(ioModeValue, ioLine); 1907 if (dioMode == null) 1908 throw new OperationNotSupportedException("Received configuration mode '" + HexUtils.integerToHexString(ioModeValue, 1) + "' is not valid."); 1909 1910 // Return the configuration mode. 1911 return dioMode; 1912 } 1913 1914 /** 1915 * Sets the digital value (high or low) to the provided IO line of this 1916 * XBee device. 1917 * 1918 * @param ioLine The IO line to set its value. 1919 * @param ioValue The IOValue to set to the IO line ({@code HIGH} or 1920 * {@code LOW}). 1921 * 1922 * @throws InterfaceNotOpenException if this device connection is not open. 1923 * @throws NullPointerException if {@code ioLine == null} or 1924 * if {@code ioValue == null}. 1925 * @throws TimeoutException if there is a timeout sending the set DIO 1926 * command. 1927 * @throws XBeeException if there is any other XBee related exception. 1928 * 1929 * @see #getIOConfiguration(IOLine) 1930 * @see #setIOConfiguration(IOLine, IOMode) 1931 * @see com.digi.xbee.api.io.IOLine 1932 * @see com.digi.xbee.api.io.IOValue 1933 * @see com.digi.xbee.api.io.IOMode#DIGITAL_OUT_HIGH 1934 * @see com.digi.xbee.api.io.IOMode#DIGITAL_OUT_LOW 1935 */ 1936 public void setDIOValue(IOLine ioLine, IOValue ioValue) throws TimeoutException, XBeeException { 1937 // Check IO line. 1938 if (ioLine == null) 1939 throw new NullPointerException("IO line cannot be null."); 1940 // Check IO value. 1941 if (ioValue == null) 1942 throw new NullPointerException("IO value cannot be null."); 1943 // Check connection. 1944 if (!connectionInterface.isOpen()) 1945 throw new InterfaceNotOpenException(); 1946 1947 setParameter(ioLine.getConfigurationATCommand(), new byte[]{(byte)ioValue.getID()}); 1948 } 1949 1950 /** 1951 * Returns the digital value of the provided IO line of this XBee device. 1952 * 1953 * <p>The provided <b>IO line must be previously configured as digital I/O 1954 * </b>. To do so, use {@code setIOConfiguration} and the following 1955 * {@code IOMode}:</p> 1956 * 1957 * <ul> 1958 * <li>{@code IOMode.DIGITAL_IN} to configure as digital input.</li> 1959 * <li>{@code IOMode.DIGITAL_OUT_HIGH} to configure as digital output, high. 1960 * </li> 1961 * <li>{@code IOMode.DIGITAL_OUT_LOW} to configure as digital output, low. 1962 * </li> 1963 * </ul> 1964 * 1965 * @param ioLine The IO line to get its digital value. 1966 * 1967 * @return The digital value corresponding to the provided IO line. 1968 * 1969 * @throws InterfaceNotOpenException if this device connection is not open. 1970 * @throws NullPointerException if {@code ioLine == null}. 1971 * @throws TimeoutException if there is a timeout sending the get IO values 1972 * command. 1973 * @throws XBeeException if there is any other XBee related exception. 1974 * 1975 * @see #getIOConfiguration(IOLine) 1976 * @see #setIOConfiguration(IOLine, IOMode) 1977 * @see com.digi.xbee.api.io.IOLine 1978 * @see com.digi.xbee.api.io.IOValue 1979 * @see com.digi.xbee.api.io.IOMode#DIGITAL_IN 1980 * @see com.digi.xbee.api.io.IOMode#DIGITAL_OUT_HIGH 1981 * @see com.digi.xbee.api.io.IOMode#DIGITAL_OUT_LOW 1982 */ 1983 public IOValue getDIOValue(IOLine ioLine) throws TimeoutException, XBeeException { 1984 // Check IO line. 1985 if (ioLine == null) 1986 throw new NullPointerException("IO line cannot be null."); 1987 1988 // Obtain an IO Sample from the XBee device. 1989 IOSample ioSample = readIOSample(); 1990 1991 // Check if the IO sample contains the expected IO line and value. 1992 if (!ioSample.hasDigitalValues() || !ioSample.getDigitalValues().containsKey(ioLine)) 1993 throw new OperationNotSupportedException("Answer does not contain digital data for " + ioLine.getName() + "."); 1994 1995 // Return the digital value. 1996 return ioSample.getDigitalValues().get(ioLine); 1997 } 1998 1999 /** 2000 * Sets the duty cycle (in %) of the provided IO line of this XBee device. 2001 * 2002 * <p>The provided <b>IO line must be</b>:</p> 2003 * 2004 * <ul> 2005 * <li><b>PWM capable</b> ({@link IOLine#hasPWMCapability()}).</li> 2006 * <li>Previously <b>configured as PWM Output</b> (use 2007 * {@code setIOConfiguration} and {@code IOMode.PWM}).</li> 2008 * </ul> 2009 * 2010 * @param ioLine The IO line to set its duty cycle value. 2011 * @param dutyCycle The duty cycle of the PWM. 2012 * 2013 * @throws IllegalArgumentException if {@code ioLine.hasPWMCapability() == false} or 2014 * if {@code value < 0} or 2015 * if {@code value > 1023}. 2016 * @throws InterfaceNotOpenException if this device connection is not open. 2017 * @throws NullPointerException if {@code ioLine == null}. 2018 * @throws TimeoutException if there is a timeout sending the set PWM duty 2019 * cycle command. 2020 * @throws XBeeException if there is any other XBee related exception. 2021 * 2022 * @see #getIOConfiguration(IOLine) 2023 * @see #getIOConfiguration(IOLine) 2024 * @see #setIOConfiguration(IOLine, IOMode) 2025 * @see #getPWMDutyCycle(IOLine) 2026 * @see com.digi.xbee.api.io.IOLine 2027 * @see com.digi.xbee.api.io.IOMode#PWM 2028 */ 2029 public void setPWMDutyCycle(IOLine ioLine, double dutyCycle) throws TimeoutException, XBeeException { 2030 // Check IO line. 2031 if (ioLine == null) 2032 throw new NullPointerException("IO line cannot be null."); 2033 // Check if the IO line has PWM capability. 2034 if (!ioLine.hasPWMCapability()) 2035 throw new IllegalArgumentException("Provided IO line does not have PWM capability."); 2036 // Check duty cycle limits. 2037 if (dutyCycle < 0 || dutyCycle > 100) 2038 throw new IllegalArgumentException("Duty Cycle must be between 0% and 100%."); 2039 // Check connection. 2040 if (!connectionInterface.isOpen()) 2041 throw new InterfaceNotOpenException(); 2042 2043 // Convert the value. 2044 int finaldutyCycle = (int)(dutyCycle * 1023.0/100.0); 2045 2046 setParameter(ioLine.getPWMDutyCycleATCommand(), ByteUtils.intToByteArray(finaldutyCycle)); 2047 } 2048 2049 /** 2050 * Gets the PWM duty cycle (in %) corresponding to the provided IO line of 2051 * this XBee device. 2052 * 2053 * <p>The provided <b>IO line must be</b>:</p> 2054 * 2055 * <ul> 2056 * <li><b>PWM capable</b> ({@link IOLine#hasPWMCapability()}).</li> 2057 * <li>Previously <b>configured as PWM Output</b> (use 2058 * {@code setIOConfiguration} and {@code IOMode.PWM}).</li> 2059 * </ul> 2060 * 2061 * @param ioLine The IO line to get its PWM duty cycle. 2062 * 2063 * @return The PWM duty cycle value corresponding to the provided IO line 2064 * (0% - 100%). 2065 * 2066 * @throws IllegalArgumentException if {@code ioLine.hasPWMCapability() == false}. 2067 * @throws InterfaceNotOpenException if this device connection is not open. 2068 * @throws NullPointerException if {@code ioLine == null}. 2069 * @throws TimeoutException if there is a timeout sending the get PWM duty 2070 * cycle command. 2071 * @throws XBeeException if there is any other XBee related exception. 2072 * 2073 * @see #getIOConfiguration(IOLine) 2074 * @see #setIOConfiguration(IOLine, IOMode) 2075 * @see #setPWMDutyCycle(IOLine, double) 2076 * @see com.digi.xbee.api.io.IOLine 2077 * @see com.digi.xbee.api.io.IOMode#PWM 2078 */ 2079 public double getPWMDutyCycle(IOLine ioLine) throws TimeoutException, XBeeException { 2080 // Check IO line. 2081 if (ioLine == null) 2082 throw new NullPointerException("IO line cannot be null."); 2083 // Check if the IO line has PWM capability. 2084 if (!ioLine.hasPWMCapability()) 2085 throw new IllegalArgumentException("Provided IO line does not have PWM capability."); 2086 // Check connection. 2087 if (!connectionInterface.isOpen()) 2088 throw new InterfaceNotOpenException(); 2089 2090 byte[] value = getParameter(ioLine.getPWMDutyCycleATCommand()); 2091 2092 // Return the PWM duty cycle value. 2093 int readValue = ByteUtils.byteArrayToInt(value); 2094 return Math.round((readValue * 100.0/1023.0) * 100.0) / 100.0; 2095 } 2096 2097 /** 2098 * Returns the analog value of the provided IO line of this XBee device. 2099 * 2100 * <p>The provided <b>IO line must be previously configured as ADC</b>. To 2101 * do so, use {@code setIOConfiguration} and {@code IOMode.ADC}.</p> 2102 * 2103 * @param ioLine The IO line to get its analog value. 2104 * 2105 * @return The analog value corresponding to the provided IO line. 2106 * 2107 * @throws InterfaceNotOpenException if this device connection is not open. 2108 * @throws NullPointerException if {@code ioLine == null}. 2109 * @throws TimeoutException if there is a timeout sending the get IO values 2110 * command. 2111 * @throws XBeeException if there is any other XBee related exception. 2112 * 2113 * @see #getIOConfiguration(IOLine) 2114 * @see #setIOConfiguration(IOLine, IOMode) 2115 * @see com.digi.xbee.api.io.IOLine 2116 * @see com.digi.xbee.api.io.IOMode#ADC 2117 */ 2118 public int getADCValue(IOLine ioLine) throws TimeoutException, XBeeException { 2119 // Check IO line. 2120 if (ioLine == null) 2121 throw new NullPointerException("IO line cannot be null."); 2122 2123 // Obtain an IO Sample from the XBee device. 2124 IOSample ioSample = readIOSample(); 2125 2126 // Check if the IO sample contains the expected IO line and value. 2127 if (!ioSample.hasAnalogValues() || !ioSample.getAnalogValues().containsKey(ioLine)) 2128 throw new OperationNotSupportedException("Answer does not contain analog data for " + ioLine.getName() + "."); 2129 2130 // Return the analog value. 2131 return ioSample.getAnalogValues().get(ioLine); 2132 } 2133 2134 /** 2135 * Sets the 64-bit destination extended address of this XBee device. 2136 * 2137 * <p>{@link XBee64BitAddress#BROADCAST_ADDRESS} is the broadcast address 2138 * for the PAN. {@link XBee64BitAddress#COORDINATOR_ADDRESS} can be used to 2139 * address the Pan Coordinator.</p> 2140 * 2141 * @param xbee64BitAddress 64-bit destination address to be configured. 2142 * 2143 * @throws InterfaceNotOpenException if this device connection is not open. 2144 * @throws NullPointerException if {@code xbee64BitAddress == null}. 2145 * @throws TimeoutException if there is a timeout sending the set 2146 * destination address command. 2147 * @throws XBeeException if there is any other XBee related exception. 2148 * 2149 * @see #getDestinationAddress() 2150 * @see com.digi.xbee.api.models.XBee64BitAddress 2151 */ 2152 public void setDestinationAddress(XBee64BitAddress xbee64BitAddress) throws TimeoutException, XBeeException { 2153 if (xbee64BitAddress == null) 2154 throw new NullPointerException("Address cannot be null."); 2155 2156 // This method needs to apply changes after modifying the destination 2157 // address, but only if the destination address could be set successfully. 2158 boolean applyChanges = isApplyConfigurationChangesEnabled(); 2159 if (applyChanges) 2160 enableApplyConfigurationChanges(false); 2161 2162 byte[] address = xbee64BitAddress.getValue(); 2163 try { 2164 setParameter("DH", Arrays.copyOfRange(address, 0, 4)); 2165 setParameter("DL", Arrays.copyOfRange(address, 4, 8)); 2166 applyChanges(); 2167 } finally { 2168 // Always restore the old value of the AC. 2169 enableApplyConfigurationChanges(applyChanges); 2170 } 2171 } 2172 2173 /** 2174 * Returns the 64-bit destination extended address of this XBee device. 2175 * 2176 * <p>{@link XBee64BitAddress#BROADCAST_ADDRESS} is the broadcast address 2177 * for the PAN. {@link XBee64BitAddress#COORDINATOR_ADDRESS} can be used to 2178 * address the Pan Coordinator.</p> 2179 * 2180 * @return 64-bit destination address. 2181 * 2182 * @throws InterfaceNotOpenException if this device connection is not open. 2183 * @throws TimeoutException if there is a timeout sending the get 2184 * destination address command. 2185 * @throws XBeeException if there is any other XBee related exception. 2186 * 2187 * @see #setDestinationAddress(XBee64BitAddress) 2188 * @see com.digi.xbee.api.models.XBee64BitAddress 2189 */ 2190 public XBee64BitAddress getDestinationAddress() throws TimeoutException, XBeeException { 2191 byte[] dh = getParameter("DH"); 2192 byte[] dl = getParameter("DL"); 2193 byte[] address = new byte[dh.length + dl.length]; 2194 2195 System.arraycopy(dh, 0, address, 0, dh.length); 2196 System.arraycopy(dl, 0, address, dh.length, dl.length); 2197 2198 return new XBee64BitAddress(address); 2199 } 2200 2201 /** 2202 * Sets the destination IPv6 address. 2203 * 2204 * @param ipv6Address Destination IPv6 address. 2205 * 2206 * @throws NullPointerException if {@code ipv6Address == null}. 2207 * @throws TimeoutException if there is a timeout setting the IPv6 2208 * destination address. 2209 * @throws XBeeException if there is any other XBee related exception. 2210 * 2211 * @see #getIPv6DestinationAddress() 2212 * @see java.net.Inet6Address 2213 * 2214 * @since 1.2.1 2215 */ 2216 public void setIPv6DestinationAddress(Inet6Address ipv6Address) throws TimeoutException, XBeeException { 2217 if (ipv6Address == null) 2218 throw new NullPointerException("Destination IPv6 address cannot be null."); 2219 2220 setParameter("DL", ipv6Address.getAddress()); 2221 } 2222 2223 /** 2224 * Returns the destination IPv6 address. 2225 * 2226 * @return The configured destination IPv6 address. 2227 * 2228 * @throws TimeoutException if there is a timeout reading the IPv6 2229 * destination address. 2230 * @throws XBeeException if there is any other XBee related exception. 2231 * 2232 * @see #setIPv6DestinationAddress(Inet6Address) 2233 * @see java.net.Inet6Address 2234 * 2235 * @since 1.2.1 2236 */ 2237 public Inet6Address getIPv6DestinationAddress() throws TimeoutException, XBeeException { 2238 try { 2239 return (Inet6Address) Inet6Address.getByAddress(getParameter("DL")); 2240 } catch (UnknownHostException e) { 2241 throw new XBeeException(e); 2242 } 2243 } 2244 2245 /** 2246 * Sets the IO sampling rate to enable periodic sampling in this XBee 2247 * device. 2248 * 2249 * <p>A sample rate of {@code 0} ms. disables this feature.</p> 2250 * 2251 * <p>All enabled digital IO and analog inputs will be sampled and 2252 * transmitted every {@code rate} milliseconds to the configured destination 2253 * address.</p> 2254 * 2255 * <p>The destination address can be configured using the 2256 * {@code setDestinationAddress(XBee64BitAddress)} method and retrieved by 2257 * {@code getDestinationAddress()}.</p> 2258 * 2259 * @param rate IO sampling rate in milliseconds. 2260 * 2261 * @throws IllegalArgumentException if {@code rate < 0} or {@code rate > 2262 * 0xFFFF}. 2263 * @throws InterfaceNotOpenException if this device connection is not open. 2264 * @throws TimeoutException if there is a timeout sending the set IO 2265 * sampling rate command. 2266 * @throws XBeeException if there is any other XBee related exception. 2267 * 2268 * @see #getDestinationAddress() 2269 * @see #setDestinationAddress(XBee64BitAddress) 2270 * @see #getIOSamplingRate() 2271 */ 2272 public void setIOSamplingRate(int rate) throws TimeoutException, XBeeException { 2273 // Check range. 2274 if (rate < 0 || rate > 0xFFFF) 2275 throw new IllegalArgumentException("Rate must be between 0 and 0xFFFF."); 2276 // Check connection. 2277 if (!connectionInterface.isOpen()) 2278 throw new InterfaceNotOpenException(); 2279 2280 setParameter("IR", ByteUtils.intToByteArray(rate)); 2281 } 2282 2283 /** 2284 * Returns the IO sampling rate of this XBee device. 2285 * 2286 * <p>A sample rate of {@code 0} means the IO sampling feature is disabled. 2287 * </p> 2288 * 2289 * <p>Periodic sampling allows this XBee module to take an IO sample and 2290 * transmit it to a remote device (configured in the destination address) 2291 * at the configured periodic rate (ms).</p> 2292 * 2293 * @return IO sampling rate in milliseconds. 2294 * 2295 * @throws InterfaceNotOpenException if this device connection is not open. 2296 * @throws TimeoutException if there is a timeout sending the get IO 2297 * sampling rate command. 2298 * @throws XBeeException if there is any other XBee related exception. 2299 * 2300 * @see #getDestinationAddress() 2301 * @see #setDestinationAddress(XBee64BitAddress) 2302 * @see #setIOSamplingRate(int) 2303 */ 2304 public int getIOSamplingRate() throws TimeoutException, XBeeException { 2305 // Check connection. 2306 if (!connectionInterface.isOpen()) 2307 throw new InterfaceNotOpenException(); 2308 2309 byte[] rate = getParameter("IR"); 2310 return ByteUtils.byteArrayToInt(rate); 2311 } 2312 2313 /** 2314 * Sets the digital IO lines of this XBee device to be monitored and 2315 * sampled whenever their status changes. 2316 * 2317 * <p>A {@code null} set of lines disables this feature.</p> 2318 * 2319 * <p>If a change is detected on an enabled digital IO pin, a digital IO 2320 * sample is immediately transmitted to the configured destination address. 2321 * </p> 2322 * 2323 * <p>The destination address can be configured using the 2324 * {@code setDestinationAddress(XBee64BitAddress)} method and retrieved by 2325 * {@code getDestinationAddress()}.</p> 2326 * 2327 * @param lines Set of IO lines to be monitored, {@code null} to disable 2328 * this feature. 2329 * 2330 * @throws InterfaceNotOpenException if this device connection is not open. 2331 * @throws TimeoutException if there is a timeout sending the set DIO 2332 * change detection command. 2333 * @throws XBeeException if there is any other XBee related exception. 2334 * 2335 * @see #getDestinationAddress() 2336 * @see #getDIOChangeDetection() 2337 * @see #setDestinationAddress(XBee64BitAddress) 2338 */ 2339 public void setDIOChangeDetection(Set<IOLine> lines) throws TimeoutException, XBeeException { 2340 // Check connection. 2341 if (!connectionInterface.isOpen()) 2342 throw new InterfaceNotOpenException(); 2343 2344 byte[] bitfield = new byte[2]; 2345 2346 if (lines != null) { 2347 for (IOLine line : lines) { 2348 int i = line.getIndex(); 2349 if (i < 8) 2350 bitfield[1] = (byte) (bitfield[1] | (1 << i)); 2351 else 2352 bitfield[0] = (byte) (bitfield[0] | (1 << i - 8)); 2353 } 2354 } 2355 2356 setParameter("IC", bitfield); 2357 } 2358 2359 /** 2360 * Returns the set of IO lines of this device that are monitored for 2361 * change detection. 2362 * 2363 * <p>A {@code null} set means the DIO change detection feature is disabled. 2364 * </p> 2365 * 2366 * <p>Modules can be configured to transmit to the configured destination 2367 * address a data sample immediately whenever a monitored digital IO line 2368 * changes state.</p> 2369 * 2370 * @return Set of digital IO lines that are monitored for change detection, 2371 * {@code null} if there are no monitored lines. 2372 * 2373 * @throws InterfaceNotOpenException if this device connection is not open. 2374 * @throws TimeoutException if there is a timeout sending the get DIO 2375 * change detection command. 2376 * @throws XBeeException if there is any other XBee related exception. 2377 * 2378 * @see #getDestinationAddress() 2379 * @see #setDestinationAddress(XBee64BitAddress) 2380 * @see #setDIOChangeDetection(Set) 2381 */ 2382 public Set<IOLine> getDIOChangeDetection() throws TimeoutException, XBeeException { 2383 // Check connection. 2384 if (!connectionInterface.isOpen()) 2385 throw new InterfaceNotOpenException(); 2386 2387 byte[] bitfield = getParameter("IC"); 2388 TreeSet<IOLine> lines = new TreeSet<IOLine>(); 2389 int mask = (bitfield[0] << 8) + (bitfield[1] & 0xFF); 2390 2391 for (int i = 0; i < 16; i++) { 2392 if (ByteUtils.isBitEnabled(mask, i)) 2393 lines.add(IOLine.getDIO(i)); 2394 } 2395 2396 if (lines.size() > 0) 2397 return lines; 2398 return null; 2399 } 2400 2401 /** 2402 * Applies changes to all command registers causing queued command register 2403 * values to be applied. 2404 * 2405 * <p>This method must be invoked if the 'apply configuration changes' 2406 * option is disabled and the changes to this XBee device parameters must 2407 * be applied.</p> 2408 * 2409 * <p>To know if the 'apply configuration changes' option is enabled, use 2410 * the {@code isApplyConfigurationChangesEnabled()} method. And to 2411 * enable/disable this feature, the method 2412 * {@code enableApplyConfigurationChanges(boolean)}.</p> 2413 * 2414 * <p>Applying changes does not imply the modifications will persist 2415 * through subsequent resets. To do so, use the {@code writeChanges()} 2416 * method.</p> 2417 * 2418 * @throws InterfaceNotOpenException if this device connection is not open. 2419 * @throws TimeoutException if there is a timeout sending the get Apply 2420 * Changes command. 2421 * @throws XBeeException if there is any other XBee related exception. 2422 * 2423 * @see #enableApplyConfigurationChanges(boolean) 2424 * @see #isApplyConfigurationChangesEnabled() 2425 * @see #setParameter(String, byte[]) 2426 * @see #writeChanges() 2427 */ 2428 public void applyChanges() throws TimeoutException, XBeeException { 2429 executeParameter("AC"); 2430 } 2431 2432 /** 2433 * Checks if the provided {@code ATCommandResponse} is valid throwing an 2434 * {@code ATCommandException} in case it is not. 2435 * 2436 * @param response The {@code ATCommandResponse} to check. 2437 * 2438 * @throws ATCommandException if {@code response == null} or 2439 * if {@code response.getResponseStatus() != ATCommandStatus.OK}. 2440 * 2441 * @see com.digi.xbee.api.models.ATCommandResponse 2442 */ 2443 protected void checkATCommandResponseIsValid(ATCommandResponse response) throws ATCommandException { 2444 if (response == null || response.getResponseStatus() == null) 2445 throw new ATCommandException(null); 2446 else if (response.getResponseStatus() != ATCommandStatus.OK) 2447 throw new ATCommandException(response.getResponseStatus()); 2448 } 2449 2450 /** 2451 * Returns an IO sample from this XBee device containing the value of all 2452 * enabled digital IO and analog input channels. 2453 * 2454 * @return An IO sample containing the value of all enabled digital IO and 2455 * analog input channels. 2456 * 2457 * @throws InterfaceNotOpenException if this device connection is not open. 2458 * @throws TimeoutException if there is a timeout getting the IO sample. 2459 * @throws XBeeException if there is any other XBee related exception. 2460 * 2461 * @see com.digi.xbee.api.io.IOSample 2462 */ 2463 public IOSample readIOSample() throws TimeoutException, XBeeException { 2464 // Check connection. 2465 if (!connectionInterface.isOpen()) 2466 throw new InterfaceNotOpenException(); 2467 2468 // Try to build an IO Sample from the sample payload. 2469 byte[] samplePayload = null; 2470 IOSample ioSample; 2471 2472 // The response to the IS command in local 802.15.4 devices is empty, 2473 // so we have to create a packet listener to receive the IO sample. 2474 if (!isRemote() && getXBeeProtocol() == XBeeProtocol.RAW_802_15_4) { 2475 executeParameter("IS"); 2476 samplePayload = receiveRaw802IOPacket(); 2477 if (samplePayload == null) 2478 throw new TimeoutException("Timeout waiting for the IO response packet."); 2479 } else 2480 samplePayload = getParameter("IS"); 2481 2482 try { 2483 ioSample = new IOSample(samplePayload); 2484 } catch (IllegalArgumentException e) { 2485 throw new XBeeException("Couldn't create the IO sample.", e); 2486 } catch (NullPointerException e) { 2487 throw new XBeeException("Couldn't create the IO sample.", e); 2488 } 2489 return ioSample; 2490 } 2491 2492 /** 2493 * Returns the latest 802.15.4 IO packet and returns its value. 2494 * 2495 * @return The value of the latest received 802.15.4 IO packet. 2496 */ 2497 private byte[] receiveRaw802IOPacket() { 2498 ioPacketReceived = false; 2499 ioPacketPayload = null; 2500 addPacketListener(IOPacketReceiveListener); 2501 synchronized (ioLock) { 2502 try { 2503 ioLock.wait(receiveTimeout); 2504 } catch (InterruptedException e) { } 2505 } 2506 removePacketListener(IOPacketReceiveListener); 2507 if (ioPacketReceived) 2508 return ioPacketPayload; 2509 return null; 2510 } 2511 2512 /** 2513 * Custom listener for 802.15.4 IO packets. It will try to receive an 2514 * 802.15.4 IO sample packet. 2515 * 2516 * <p>When an IO sample packet is received, it saves its payload and 2517 * notifies the object that was waiting for the reception.</p> 2518 */ 2519 private IPacketReceiveListener IOPacketReceiveListener = new IPacketReceiveListener() { 2520 /* 2521 * (non-Javadoc) 2522 * @see com.digi.xbee.api.listeners.IPacketReceiveListener#packetReceived(com.digi.xbee.api.packet.XBeePacket) 2523 */ 2524 @Override 2525 public void packetReceived(XBeePacket receivedPacket) { 2526 // Discard non API packets. 2527 if (!(receivedPacket instanceof XBeeAPIPacket)) 2528 return; 2529 // If we already have received an IO packet, ignore this packet. 2530 if (ioPacketReceived) 2531 return; 2532 2533 // Save the packet value (IO sample payload) 2534 switch (((XBeeAPIPacket)receivedPacket).getFrameType()) { 2535 case IO_DATA_SAMPLE_RX_INDICATOR: 2536 ioPacketPayload = ((IODataSampleRxIndicatorPacket)receivedPacket).getRFData(); 2537 break; 2538 case RX_IO_16: 2539 ioPacketPayload = ((RX16IOPacket)receivedPacket).getRFData(); 2540 break; 2541 case RX_IO_64: 2542 ioPacketPayload = ((RX64IOPacket)receivedPacket).getRFData(); 2543 break; 2544 default: 2545 return; 2546 } 2547 // Set the IO packet received flag. 2548 ioPacketReceived = true; 2549 2550 // Continue execution by notifying the lock object. 2551 synchronized (ioLock) { 2552 ioLock.notify(); 2553 } 2554 } 2555 }; 2556 2557 /** 2558 * Performs a software reset on this XBee device and blocks until the 2559 * process is completed. 2560 * 2561 * @throws TimeoutException if the configured time expires while waiting 2562 * for the command reply. 2563 * @throws XBeeException if there is any other XBee related exception. 2564 */ 2565 abstract public void reset() throws TimeoutException, XBeeException; 2566 2567 /** 2568 * Sets the given parameter with the provided value in this XBee device. 2569 * 2570 * <p>If the 'apply configuration changes' option is enabled in this device, 2571 * the configured value for the given parameter will be immediately applied, 2572 * if not the method {@code applyChanges()} must be invoked to apply it.</p> 2573 * 2574 * <p>Use:</p> 2575 * <ul> 2576 * <li>Method {@code isApplyConfigurationChangesEnabled()} to know 2577 * if the 'apply configuration changes' option is enabled.</li> 2578 * <li>Method {@code enableApplyConfigurationChanges(boolean)} to enable or 2579 * disable this option.</li> 2580 * </ul> 2581 * 2582 * <p>To make parameter modifications persist through subsequent resets use 2583 * the {@code writeChanges()} method.</p> 2584 * 2585 * @param parameter The name of the parameter to be set. 2586 * @param parameterValue The value of the parameter to set. 2587 * 2588 * @throws IllegalArgumentException if {@code parameter.length() != 2}. 2589 * @throws NullPointerException if {@code parameter == null} or 2590 * if {@code parameterValue == null}. 2591 * @throws TimeoutException if there is a timeout setting the parameter. 2592 * @throws XBeeException if {@code parameter} is not supported by the module or 2593 * if {@code parameterValue} is not supported or 2594 * if there is any other XBee related exception. 2595 * 2596 * @see #applyChanges() 2597 * @see #enableApplyConfigurationChanges(boolean) 2598 * @see #executeParameter(String) 2599 * @see #getParameter(String) 2600 * @see #isApplyConfigurationChangesEnabled() 2601 * @see #writeChanges() 2602 */ 2603 public void setParameter(String parameter, byte[] parameterValue) throws TimeoutException, XBeeException { 2604 if (parameterValue == null) 2605 throw new NullPointerException("Value of the parameter cannot be null."); 2606 2607 sendParameter(parameter, parameterValue); 2608 } 2609 2610 /** 2611 * Gets the value of the given parameter from this XBee device. 2612 * 2613 * @param parameter The name of the parameter to retrieve its value. 2614 * 2615 * @return A byte array containing the value of the parameter. 2616 * 2617 * @throws IllegalArgumentException if {@code parameter.length() != 2}. 2618 * @throws NullPointerException if {@code parameter == null}. 2619 * @throws TimeoutException if there is a timeout getting the parameter value. 2620 * @throws XBeeException if {@code parameter} is not supported by the module or 2621 * if there is any other XBee related exception. 2622 * 2623 * @see #executeParameter(String) 2624 * @see #setParameter(String, byte[]) 2625 */ 2626 public byte[] getParameter(String parameter) throws TimeoutException, XBeeException { 2627 byte[] parameterValue = sendParameter(parameter, null); 2628 2629 // Check if the response is null, if so throw an exception (maybe it was a write-only parameter). 2630 if (parameterValue == null) 2631 throw new OperationNotSupportedException("Couldn't get the '" + parameter + "' value."); 2632 return parameterValue; 2633 } 2634 2635 /** 2636 * Executes the given command in this XBee device. 2637 * 2638 * <p>This method is intended to be used for those AT parameters that cannot 2639 * be read or written, they just execute some action in the XBee module.</p> 2640 * 2641 * @param parameter The AT command to be executed. 2642 * 2643 * @throws IllegalArgumentException if {@code parameter.length() != 2}. 2644 * @throws NullPointerException if {@code parameter == null}. 2645 * @throws TimeoutException if there is a timeout executing the parameter. 2646 * @throws XBeeException if {@code parameter} is not supported by the module or 2647 * if there is any other XBee related exception. 2648 * 2649 * @see #getParameter(String) 2650 * @see #setParameter(String, byte[]) 2651 */ 2652 public void executeParameter(String parameter) throws TimeoutException, XBeeException { 2653 sendParameter(parameter, null); 2654 } 2655 2656 /** 2657 * Sends the given AT parameter to this XBee device with an optional 2658 * argument or value and returns the response (likely the value) of that 2659 * parameter in a byte array format. 2660 * 2661 * @param parameter The name of the AT command to be executed. 2662 * @param parameterValue The value of the parameter to set (if any). 2663 * 2664 * @return A byte array containing the value of the parameter. 2665 * 2666 * @throws IllegalArgumentException if {@code parameter.length() != 2}. 2667 * @throws NullPointerException if {@code parameter == null}. 2668 * @throws TimeoutException if there is a timeout executing the parameter. 2669 * @throws XBeeException if {@code parameter} is not supported by the module or 2670 * if {@code parameterValue} is not supported or 2671 * if there is any other XBee related exception. 2672 * 2673 * @see #getParameter(String) 2674 * @see #executeParameter(String) 2675 * @see #setParameter(String, byte[]) 2676 */ 2677 private byte[] sendParameter(String parameter, byte[] parameterValue) throws TimeoutException, XBeeException { 2678 if (parameter == null) 2679 throw new NullPointerException("Parameter cannot be null."); 2680 if (parameter.length() != 2) 2681 throw new IllegalArgumentException("Parameter must contain exactly 2 characters."); 2682 2683 ATCommand atCommand = new ATCommand(parameter, parameterValue); 2684 2685 // Create and send the AT Command. 2686 ATCommandResponse response = null; 2687 try { 2688 response = sendATCommand(atCommand); 2689 } catch (IOException e) { 2690 throw new XBeeException("Error writing in the communication interface.", e); 2691 } 2692 2693 // Check if AT Command response is valid. 2694 checkATCommandResponseIsValid(response); 2695 2696 // Return the response value. 2697 return response.getResponse(); 2698 } 2699 2700 /* 2701 * (non-Javadoc) 2702 * @see java.lang.Object#toString() 2703 */ 2704 @Override 2705 public String toString() { 2706 String id = getNodeID() == null ? "" : getNodeID(); 2707 String addr64 = get64BitAddress() == null || get64BitAddress().equals(XBee64BitAddress.UNKNOWN_ADDRESS) ? 2708 "" : get64BitAddress().toString(); 2709 2710 if (id.length() == 0 && addr64.length() == 0) 2711 return connectionInterface.toString(); 2712 2713 StringBuilder message = new StringBuilder(connectionInterface.toString()); 2714 message.append(addr64); 2715 if (id.length() > 0) { 2716 message.append(" ("); 2717 message.append(id); 2718 message.append(")"); 2719 } 2720 message.append(" - "); 2721 2722 return message.toString(); 2723 } 2724 2725 /** 2726 * Enables or disables the 'apply configuration changes' option for this 2727 * device. 2728 * 2729 * <p>Enabling this option means that when any parameter of this XBee 2730 * device is set, it will be also applied.</p> 2731 * 2732 * <p>If this option is disabled, the method {@code applyChanges()} must be 2733 * used in order to apply the changes in all the parameters that were 2734 * previously set.</p> 2735 * 2736 * @param enabled {@code true} to apply configuration changes when an XBee 2737 * parameter is set, {@code false} otherwise. 2738 * 2739 * @see #applyChanges() 2740 * @see #isApplyConfigurationChangesEnabled() 2741 */ 2742 public void enableApplyConfigurationChanges(boolean enabled) { 2743 applyConfigurationChanges = enabled; 2744 } 2745 2746 /** 2747 * Returns whether the 'apply configuration changes' option is enabled in 2748 * this device. 2749 * 2750 * <p>If this option is enabled, when any parameter of this XBee device is 2751 * set, it will be also applied.</p> 2752 * 2753 * <p>If this option is disabled, the method {@code applyChanges()} must be 2754 * used in order to apply the changes in all the parameters that were 2755 * previously set.</p> 2756 * 2757 * @return {@code true} if the option is enabled, {@code false} otherwise. 2758 * 2759 * @see #applyChanges() 2760 * @see #enableApplyConfigurationChanges(boolean) 2761 */ 2762 public boolean isApplyConfigurationChangesEnabled() { 2763 return applyConfigurationChanges; 2764 } 2765 2766 /** 2767 * Configures the 16-bit address (network address) of this XBee device with 2768 * the provided one. 2769 * 2770 * @param xbee16BitAddress The new 16-bit address. 2771 * 2772 * @throws InterfaceNotOpenException if this device connection is not open. 2773 * @throws NullPointerException if {@code xbee16BitAddress == null}. 2774 * @throws TimeoutException if there is a timeout setting the address. 2775 * @throws XBeeException if there is any other XBee related exception. 2776 * 2777 * @see #get16BitAddress() 2778 * @see com.digi.xbee.api.models.XBee16BitAddress 2779 */ 2780 protected void set16BitAddress(XBee16BitAddress xbee16BitAddress) throws TimeoutException, XBeeException { 2781 if (xbee16BitAddress == null) 2782 throw new NullPointerException("16-bit address canot be null."); 2783 2784 setParameter("MY", xbee16BitAddress.getValue()); 2785 2786 this.xbee16BitAddress = xbee16BitAddress; 2787 } 2788 2789 /** 2790 * Returns the operating PAN ID (Personal Area Network Identifier) of 2791 * this XBee device. 2792 * 2793 * <p>For modules to communicate they must be configured with the same 2794 * identifier. Only modules with matching IDs can communicate with each 2795 * other.This parameter allows multiple networks to co-exist on the same 2796 * physical channel.</p> 2797 * 2798 * @return The operating PAN ID of this XBee device. 2799 * 2800 * @throws InterfaceNotOpenException if this device connection is not open. 2801 * @throws TimeoutException if there is a timeout getting the PAN ID. 2802 * @throws XBeeException if there is any other XBee related exception. 2803 * 2804 * @see #setPANID(byte[]) 2805 */ 2806 public byte[] getPANID() throws TimeoutException, XBeeException { 2807 switch (getXBeeProtocol()) { 2808 case ZIGBEE: 2809 return getParameter("OP"); 2810 default: 2811 return getParameter("ID"); 2812 } 2813 } 2814 2815 /** 2816 * Sets the PAN ID (Personal Area Network Identifier) of this XBee device. 2817 * 2818 * <p>For modules to communicate they must be configured with the same 2819 * identifier. Only modules with matching IDs can communicate with each 2820 * other.This parameter allows multiple networks to co-exist on the same 2821 * physical channel.</p> 2822 * 2823 * @param panID The new PAN ID of this XBee device. 2824 * 2825 * @throws IllegalArgumentException if {@code panID.length == 0} or 2826 * if {@code panID.length > 8}. 2827 * @throws InterfaceNotOpenException if this device connection is not open. 2828 * @throws NullPointerException if {@code panID == null}. 2829 * @throws TimeoutException if there is a timeout setting the PAN ID. 2830 * @throws XBeeException if there is any other XBee related exception. 2831 * 2832 * @see #getPANID() 2833 */ 2834 public void setPANID(byte[] panID) throws TimeoutException, XBeeException { 2835 if (panID == null) 2836 throw new NullPointerException("PAN ID cannot be null."); 2837 if (panID.length == 0) 2838 throw new IllegalArgumentException("Length of the PAN ID cannot be 0."); 2839 if (panID.length > 8) 2840 throw new IllegalArgumentException("Length of the PAN ID cannot be longer than 8 bytes."); 2841 2842 setParameter("ID", panID); 2843 } 2844 2845 /** 2846 * Returns the output power level at which this XBee device transmits 2847 * conducted power. 2848 * 2849 * @return The output power level of this XBee device. 2850 * 2851 * @throws InterfaceNotOpenException if this device connection is not open. 2852 * @throws TimeoutException if there is a timeout getting the power level. 2853 * @throws XBeeException if there is any other XBee related exception. 2854 * 2855 * @see #setPowerLevel(PowerLevel) 2856 * @see com.digi.xbee.api.models.PowerLevel 2857 */ 2858 public PowerLevel getPowerLevel() throws TimeoutException, XBeeException { 2859 byte[] powerLevelValue = getParameter("PL"); 2860 return PowerLevel.get(ByteUtils.byteArrayToInt(powerLevelValue)); 2861 } 2862 2863 /** 2864 * Sets the output power level at which this XBee device transmits 2865 * conducted power. 2866 * 2867 * @param powerLevel The new output power level to be set in this XBee 2868 * device. 2869 * 2870 * @throws InterfaceNotOpenException if this device connection is not open. 2871 * @throws NullPointerException if {@code powerLevel == null}. 2872 * @throws TimeoutException if there is a timeout setting the power level. 2873 * @throws XBeeException if there is any other XBee related exception. 2874 * 2875 * @see #getPowerLevel() 2876 * @see com.digi.xbee.api.models.PowerLevel 2877 */ 2878 public void setPowerLevel(PowerLevel powerLevel) throws TimeoutException, XBeeException { 2879 if (powerLevel == null) 2880 throw new NullPointerException("Power level cannot be null."); 2881 2882 setParameter("PL", ByteUtils.intToByteArray(powerLevel.getValue())); 2883 } 2884 2885 /** 2886 * Returns the current association status of this XBee device. 2887 * 2888 * <p>It indicates occurrences of errors during the last association 2889 * request.</p> 2890 * 2891 * @return The association indication status of the XBee device. 2892 * 2893 * @throws InterfaceNotOpenException if this device connection is not open. 2894 * @throws TimeoutException if there is a timeout getting the association 2895 * indication status. 2896 * @throws XBeeException if there is any other XBee related exception. 2897 * 2898 * @see #forceDisassociate() 2899 * @see com.digi.xbee.api.models.AssociationIndicationStatus 2900 */ 2901 protected AssociationIndicationStatus getAssociationIndicationStatus() throws TimeoutException, XBeeException { 2902 byte[] associationIndicationValue = getParameter("AI"); 2903 return AssociationIndicationStatus.get(ByteUtils.byteArrayToInt(associationIndicationValue)); 2904 } 2905 2906 /** 2907 * Forces this XBee device to immediately disassociate from the network and 2908 * re-attempt to associate. 2909 * 2910 * <p>Only valid for End Devices.</p> 2911 * 2912 * @throws InterfaceNotOpenException if this device connection is not open. 2913 * @throws TimeoutException if there is a timeout executing the 2914 * disassociation command. 2915 * @throws XBeeException if there is any other XBee related exception. 2916 * 2917 * @see #getAssociationIndicationStatus() 2918 */ 2919 protected void forceDisassociate() throws TimeoutException, XBeeException { 2920 executeParameter("DA"); 2921 } 2922 2923 /** 2924 * Writes configurable parameter values to the non-volatile memory of this 2925 * XBee device so that parameter modifications persist through subsequent 2926 * resets. 2927 * 2928 * <p>Parameters values remain in this device's memory until overwritten by 2929 * subsequent use of this method.</p> 2930 * 2931 * <p>If changes are made without writing them to non-volatile memory, the 2932 * module reverts back to previously saved parameters the next time the 2933 * module is powered-on.</p> 2934 * 2935 * <p>Writing the parameter modifications does not mean those values are 2936 * immediately applied, this depends on the status of the 'apply 2937 * configuration changes' option. Use method 2938 * {@code isApplyConfigurationChangesEnabled()} to get its status and 2939 * {@code enableApplyConfigurationChanges(boolean)} to enable/disable the 2940 * option. If it is disable method {@code applyChanges()} can be used in 2941 * order to manually apply the changes.</p> 2942 * 2943 * @throws InterfaceNotOpenException if this device connection is not open. 2944 * @throws TimeoutException if there is a timeout executing the write 2945 * changes command. 2946 * @throws XBeeException if there is any other XBee related exception. 2947 * 2948 * @see #applyChanges() 2949 * @see #enableApplyConfigurationChanges(boolean) 2950 * @see #isApplyConfigurationChangesEnabled() 2951 * @see #setParameter(String, byte[]) 2952 */ 2953 public void writeChanges() throws TimeoutException, XBeeException { 2954 executeParameter("WR"); 2955 } 2956 2957 /** 2958 * Enables the Bluetooth interface of this XBee device. 2959 * 2960 * <p>To work with this interface, you must also configure the Bluetooth 2961 * password if not done previously. You can use the 2962 * {@link #updateBluetoothPassword(String)} method for that purpose.</p> 2963 * 2964 * <p>Note that your device must have Bluetooth Low Energy support to use 2965 * this method.</p> 2966 * 2967 * @throws TimeoutException if there is a timeout enabling the interface. 2968 * @throws XBeeException if there is any other XBee related exception. 2969 * 2970 * @see #disableBluetooth() 2971 * @see #updateBluetoothPassword(String) 2972 * 2973 * @since 1.3.0 2974 */ 2975 public void enableBluetooth() throws TimeoutException, XBeeException { 2976 enableBluetooth(true); 2977 } 2978 2979 /** 2980 * Disables the Bluetooth interface of this XBee device. 2981 * 2982 * <p>Note that your device must have Bluetooth Low Energy support to use 2983 * this method.</p> 2984 * 2985 * @throws TimeoutException if there is a timeout disabling the interface. 2986 * @throws XBeeException if there is any other XBee related exception. 2987 * 2988 * @see #enableBluetooth() 2989 * 2990 * @since 1.3.0 2991 */ 2992 public void disableBluetooth() throws TimeoutException, XBeeException { 2993 enableBluetooth(false); 2994 } 2995 2996 /** 2997 * Enables or disables the Bluetooth interface of this XBee device. 2998 * 2999 * @param enable {@code true} to enable the Bluetooth interface, 3000 * {@code false} to disable it. 3001 * 3002 * @throws TimeoutException if there is a timeout enabling or disabling the 3003 * interface. 3004 * @throws XBeeException if there is any other XBee related exception. 3005 * 3006 * @since 1.3.0 3007 */ 3008 private void enableBluetooth(boolean enable) throws TimeoutException, XBeeException { 3009 setParameter("BT", new byte[] {(byte) (enable ? 0x01 : 0x00)}); 3010 writeChanges(); 3011 applyChanges(); 3012 } 3013 3014 /** 3015 * Reads and returns the EUI-48 Bluetooth MAC address of this XBee device 3016 * in a format such as {@code 00112233AABB}. 3017 * 3018 * <p>Note that your device must have Bluetooth Low Energy support to use 3019 * this method.</p> 3020 * 3021 * @return The Bluetooth MAC address. 3022 * 3023 * @throws TimeoutException if there is a timeout reading the MAC address. 3024 * @throws XBeeException if there is any other XBee related exception. 3025 * 3026 * @since 1.3.0 3027 */ 3028 public String getBluetoothMacAddress() throws TimeoutException, XBeeException { 3029 return HexUtils.byteArrayToHexString(getParameter("BL")); 3030 } 3031 3032 /** 3033 * Changes the password of this Bluetooth device with the new one provided. 3034 * 3035 * <p>Note that your device must have Bluetooth Low Energy support to use 3036 * this method.</p> 3037 * 3038 * @param newPassword New Bluetooth password. 3039 * 3040 * @throws TimeoutException if there is a timeout changing the Bluetooth 3041 * password. 3042 * @throws XBeeException if there is any other XBee related exception. 3043 * 3044 * @since 1.3.0 3045 */ 3046 public void updateBluetoothPassword(String newPassword) throws TimeoutException, XBeeException { 3047 // Generate a new salt and verifier. 3048 byte[] salt = SrpUtils.generateSalt(); 3049 byte[] verifier; 3050 try { 3051 verifier = SrpUtils.generateVerifier(salt, newPassword); 3052 } catch (IOException | NoSuchAlgorithmException e) { 3053 throw new XBeeException(e); 3054 } 3055 3056 // Set the salt. 3057 setParameter("$S", salt); 3058 3059 // Set the verifier (split in 4 settings). 3060 int index = 0; 3061 int atLength = verifier.length / 4; 3062 3063 setParameter("$V", Arrays.copyOfRange(verifier, index, index + atLength)); 3064 index += atLength; 3065 setParameter("$W", Arrays.copyOfRange(verifier, index, index + atLength)); 3066 index += atLength; 3067 setParameter("$X", Arrays.copyOfRange(verifier, index, index + atLength)); 3068 index += atLength; 3069 setParameter("$Y", Arrays.copyOfRange(verifier, index, index + atLength)); 3070 3071 // Write and apply changes. 3072 writeChanges(); 3073 applyChanges(); 3074 } 3075 3076 /** 3077 * Opens the connection interface associated with this XBee device. 3078 * 3079 * <p>When opening the device an information reading process is 3080 * automatically performed. This includes:</p> 3081 * 3082 * <ul> 3083 * <li>64-bit address.</li> 3084 * <li>Node Identifier.</li> 3085 * <li>Hardware version.</li> 3086 * <li>Firmware version.</li> 3087 * <li>XBee device protocol.</li> 3088 * <li>16-bit address (not for DigiMesh modules).</li> 3089 * </ul> 3090 * 3091 * @throws BluetoothAuthenticationException if there is any problem in the 3092 * Bluetooth authentication. 3093 * @throws InterfaceAlreadyOpenException if this device connection is 3094 * already open. 3095 * @throws XBeeException if there is any problem opening this device 3096 * connection. 3097 * 3098 * @see #close() 3099 * @see #isOpen() 3100 */ 3101 protected void open() throws XBeeException { 3102 logger.info(toString() + "Opening the connection interface..."); 3103 3104 if (isRemote()) 3105 throw new OperationNotSupportedException("Remote devices cannot be open."); 3106 3107 // First, verify that the connection is not already open. 3108 if (connectionInterface.isOpen()) 3109 throw new InterfaceAlreadyOpenException(); 3110 3111 // Connect the interface. 3112 connectionInterface.open(); 3113 3114 logger.info(toString() + "Connection interface open."); 3115 3116 // Initialize the data reader. 3117 dataReader = new DataReader(connectionInterface, operatingMode, this); 3118 dataReader.start(); 3119 3120 // Wait 10 milliseconds until the dataReader thread is started. 3121 // This is because when the connection is opened immediately after 3122 // closing it, there is sometimes a concurrency problem and the 3123 // dataReader thread never dies. 3124 try { 3125 Thread.sleep(10); 3126 } catch (InterruptedException e) {} 3127 3128 if (connectionInterface.getConnectionType() == ConnectionType.BLUETOOTH) { 3129 // The communication in Bluetooth is always done through API frames 3130 // regardless of the AP setting. 3131 operatingMode = OperatingMode.API; 3132 dataReader.setXBeeReaderMode(operatingMode); 3133 3134 // Perform the Bluetooth authentication. 3135 try { 3136 logger.info(toString() + "Starting Bluetooth authentication..."); 3137 BluetoothAuthentication auth = new BluetoothAuthentication(this, bluetoothPassword); 3138 auth.authenticate(); 3139 ((AbstractBluetoothInterface) connectionInterface).setEncryptionKeys(auth.getKey(), auth.getTxNonce(), auth.getRxNonce()); 3140 logger.info(toString() + "Authentication finished successfully."); 3141 } catch (BluetoothAuthenticationException e) { 3142 close(); 3143 throw e; 3144 } 3145 } else { 3146 // Determine the operating mode of the XBee device if it is unknown. 3147 if (operatingMode == OperatingMode.UNKNOWN) 3148 operatingMode = determineOperatingMode(); 3149 3150 // Check if the operating mode is a valid and supported one. 3151 if (operatingMode == OperatingMode.UNKNOWN) { 3152 close(); 3153 throw new InvalidOperatingModeException("Could not determine operating mode."); 3154 } else if (operatingMode != OperatingMode.API && operatingMode != OperatingMode.API_ESCAPE) { 3155 close(); 3156 throw new InvalidOperatingModeException(operatingMode); 3157 } 3158 } 3159 3160 // Read the device info (obtain its parameters and protocol). 3161 try { 3162 readDeviceInfo(); 3163 } catch (ATCommandException e) { 3164 throw new XBeeException("Error reading device information.", e); 3165 } 3166 } 3167 3168 /** 3169 * Closes the connection interface associated with this XBee device. 3170 * 3171 * @see #isOpen() 3172 * @see #open() 3173 */ 3174 protected void close() { 3175 // Stop XBee reader. 3176 if (dataReader != null && dataReader.isRunning()) 3177 dataReader.stopReader(); 3178 // Close interface. 3179 connectionInterface.close(); 3180 logger.info(toString() + "Connection interface closed."); 3181 } 3182 3183 /** 3184 * Determines the operating mode of this XBee device. 3185 * 3186 * @return The operating mode of the XBee device. 3187 * 3188 * @throws InterfaceNotOpenException if this device connection is not open. 3189 * @throws OperationNotSupportedException if the packet is being sent from 3190 * a remote device. 3191 * 3192 * @see com.digi.xbee.api.models.OperatingMode 3193 */ 3194 protected OperatingMode determineOperatingMode() throws OperationNotSupportedException { 3195 try { 3196 // Check if device is in API or API Escaped operating modes. 3197 operatingMode = OperatingMode.API; 3198 dataReader.setXBeeReaderMode(operatingMode); 3199 3200 ATCommandResponse response = sendATCommand(new ATCommand("AP")); 3201 if (response.getResponse() != null && response.getResponse().length > 0) { 3202 if (response.getResponse()[0] != OperatingMode.API.getID()) { 3203 operatingMode = OperatingMode.API_ESCAPE; 3204 dataReader.setXBeeReaderMode(operatingMode); 3205 } 3206 logger.debug(toString() + "Using {}.", operatingMode.getName()); 3207 return operatingMode; 3208 } 3209 } catch (TimeoutException e) { 3210 // Check if device is in AT operating mode. 3211 operatingMode = OperatingMode.AT; 3212 dataReader.setXBeeReaderMode(operatingMode); 3213 3214 try { 3215 // It is necessary to wait at least 1 second to enter in 3216 // command mode after sending any data to the device. 3217 Thread.sleep(TIMEOUT_BEFORE_COMMAND_MODE); 3218 // Try to enter in AT command mode and get the actual mode. 3219 if (enterATCommandMode()) { 3220 operatingMode = getActualMode(); 3221 logger.debug(toString() + "Using {}.", operatingMode.getName()); 3222 // Update the data reader with the correct mode. 3223 dataReader.setXBeeReaderMode(operatingMode); 3224 return operatingMode; 3225 } 3226 } catch (TimeoutException e1) { 3227 logger.error(e1.getMessage(), e1); 3228 } catch (InvalidOperatingModeException e1) { 3229 logger.error(e1.getMessage(), e1); 3230 } catch (InterruptedException e1) { 3231 logger.error(e1.getMessage(), e1); 3232 } finally { 3233 // Exit AT command mode. 3234 exitATCommandMode(); 3235 } 3236 } catch (InvalidOperatingModeException e) { 3237 logger.error("Invalid operating mode", e); 3238 } catch (IOException e) { 3239 logger.error(e.getMessage(), e); 3240 } 3241 return OperatingMode.UNKNOWN; 3242 } 3243 3244 /** 3245 * Attempts to put this device in AT Command mode. Only valid if device is 3246 * working in AT mode. 3247 * 3248 * @return {@code true} if the device entered in AT command mode, 3249 * {@code false} otherwise. 3250 * 3251 * @throws InterfaceNotOpenException if this device connection is not open. 3252 * @throws InvalidOperatingModeException if the operating mode cannot be 3253 * determined or is not supported. 3254 * @throws TimeoutException if the configured time for this device expires. 3255 */ 3256 private boolean enterATCommandMode() throws InvalidOperatingModeException, TimeoutException { 3257 if (!connectionInterface.isOpen()) 3258 throw new InterfaceNotOpenException(); 3259 if (operatingMode == OperatingMode.API || operatingMode == OperatingMode.API_ESCAPE) 3260 throw new InvalidOperatingModeException("Invalid mode. Command mode can be only accessed while in AT mode."); 3261 3262 // Enter in AT command mode (send '+++'). The process waits 1,5 seconds for the 'OK\n'. 3263 byte[] readData = new byte[256]; 3264 try { 3265 // Send the command mode sequence. 3266 connectionInterface.writeData(COMMAND_MODE_CHAR.getBytes()); 3267 connectionInterface.writeData(COMMAND_MODE_CHAR.getBytes()); 3268 connectionInterface.writeData(COMMAND_MODE_CHAR.getBytes()); 3269 3270 // Wait some time to let the module generate a response. 3271 Thread.sleep(DEFAULT_GUARD_TIME); 3272 3273 // Read data from the device (it should answer with 'OK\r'). 3274 int readBytes = connectionInterface.readData(readData); 3275 if (readBytes < COMMAND_MODE_OK.length()) 3276 throw new TimeoutException(); 3277 3278 // Check if the read data is 'OK\r'. 3279 String readString = new String(readData, 0, readBytes); 3280 if (!readString.contains(COMMAND_MODE_OK)) 3281 return false; 3282 3283 // Read data was 'OK\r'. 3284 return true; 3285 } catch (IOException | InterruptedException e) { 3286 logger.error(e.getMessage(), e); 3287 } 3288 return false; 3289 } 3290 3291 /** 3292 * Exits AT command mode. The XBee device has to be in command mode. 3293 * 3294 * @throws InterfaceNotOpenException if this device connection is not open. 3295 * 3296 * @since 1.3.1 3297 */ 3298 private void exitATCommandMode() { 3299 if (!connectionInterface.isOpen()) 3300 throw new InterfaceNotOpenException(); 3301 3302 try { 3303 // Send the exit ('ATCN\r') command. 3304 connectionInterface.writeData(COMMAND_MODE_EXIT.getBytes()); 3305 // Wait the guard time. 3306 Thread.sleep(DEFAULT_GUARD_TIME); 3307 } catch (IOException | InterruptedException e) { 3308 logger.error(e.getMessage(), e); 3309 } 3310 } 3311 3312 /** 3313 * Gets and returns the actual operating mode of the XBee device reading 3314 * the {@code AP} parameter in AT command mode. 3315 * 3316 * @return The actual operating mode of the XBee device or 3317 * {@code OperatingMode.UNKNOWN} if the mode could not be read. 3318 * 3319 * @throws InterfaceNotOpenException if this device connection is not open. 3320 * 3321 * @since 1.3.1 3322 */ 3323 private OperatingMode getActualMode() throws InvalidOperatingModeException { 3324 if (!connectionInterface.isOpen()) 3325 throw new InterfaceNotOpenException(); 3326 3327 byte[] readData = new byte[256]; 3328 try { 3329 // Clear the serial input stream. 3330 if (connectionInterface instanceof AbstractSerialPort) 3331 ((AbstractSerialPort)connectionInterface).purge(); 3332 // Send the 'AP' command. 3333 connectionInterface.writeData(COMMAND_MODE_AP.getBytes()); 3334 Thread.sleep(100); 3335 // Read the 'AP' answer. 3336 int readBytes = connectionInterface.readData(readData); 3337 if (readBytes == 0) 3338 return OperatingMode.UNKNOWN; 3339 // Return the corresponding operating mode for the AP answer. 3340 return OperatingMode.get(Integer.parseInt(new String(readData).trim(), 16)); 3341 } catch (IOException | NumberFormatException | InterruptedException e) { 3342 logger.error(e.getMessage(), e); 3343 } 3344 return OperatingMode.UNKNOWN; 3345 } 3346 3347 /** 3348 * Returns whether the connection interface associated to this device is 3349 * already open. 3350 * 3351 * @return {@code true} if the interface is open, {@code false} otherwise. 3352 * 3353 * @see #close() 3354 * @see #open() 3355 */ 3356 protected boolean isOpen() { 3357 if (connectionInterface != null) 3358 return connectionInterface.isOpen(); 3359 return false; 3360 } 3361 3362 /** 3363 * Returns the network associated with this XBee device. 3364 * 3365 * @return The XBee network of the device. 3366 * 3367 * @throws InterfaceNotOpenException if this device connection is not open. 3368 * 3369 * @see XBeeNetwork 3370 */ 3371 protected XBeeNetwork getNetwork() { 3372 if (isRemote()) 3373 throw new RuntimeException("Remote devices do not have network."); 3374 3375 if (!isOpen()) 3376 throw new InterfaceNotOpenException(); 3377 3378 if (network == null) 3379 network = new XBeeNetwork(this); 3380 return network; 3381 } 3382 3383 /** 3384 * Returns this XBee device configured timeout for receiving packets in 3385 * synchronous operations. 3386 * 3387 * @return The current receive timeout in milliseconds. 3388 * 3389 * @see #setReceiveTimeout(int) 3390 */ 3391 protected int getReceiveTimeout() { 3392 return receiveTimeout; 3393 } 3394 3395 /** 3396 * Configures this XBee device timeout in milliseconds for receiving 3397 * packets in synchronous operations. 3398 * 3399 * @param receiveTimeout The new receive timeout in milliseconds. 3400 * 3401 * @throws IllegalArgumentException if {@code receiveTimeout < 0}. 3402 * 3403 * @see #getReceiveTimeout() 3404 */ 3405 protected void setReceiveTimeout(int receiveTimeout) { 3406 if (receiveTimeout < 0) 3407 throw new IllegalArgumentException("Receive timeout cannot be less than 0."); 3408 3409 this.receiveTimeout = receiveTimeout; 3410 } 3411 3412 /** 3413 * Sends asynchronously the provided data to the XBee device of the network 3414 * corresponding to the given 64-bit address. 3415 * 3416 * <p>Asynchronous transmissions do not wait for answer from the remote 3417 * device or for transmit status packet.</p> 3418 * 3419 * @param address The 64-bit address of the XBee that will receive the data. 3420 * @param data Byte array containing the data to be sent. 3421 * 3422 * @throws InterfaceNotOpenException if this device connection is not open. 3423 * @throws NullPointerException if {@code address == null} or 3424 * if {@code data == null}. 3425 * @throws XBeeException if there is any XBee related exception. 3426 * 3427 * @see #sendData(RemoteXBeeDevice, byte[]) 3428 * @see #sendData(XBee64BitAddress, byte[]) 3429 * @see #sendData(XBee64BitAddress, XBee16BitAddress, byte[]) 3430 * @see #sendDataAsync(RemoteXBeeDevice, byte[]) 3431 * @see #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[]) 3432 * @see com.digi.xbee.api.models.XBee64BitAddress 3433 */ 3434 protected void sendDataAsync(XBee64BitAddress address, byte[] data) throws XBeeException { 3435 // Verify the parameters are not null, if they are null, throw an exception. 3436 if (address == null) 3437 throw new NullPointerException("Address cannot be null"); 3438 if (data == null) 3439 throw new NullPointerException("Data cannot be null"); 3440 3441 // Check if device is remote. 3442 if (isRemote()) 3443 throw new OperationNotSupportedException("Cannot send data to a remote device from a remote device."); 3444 3445 logger.debug(toString() + "Sending data asynchronously to {} >> {}.", address, HexUtils.prettyHexString(data)); 3446 3447 XBeePacket xbeePacket; 3448 switch (getXBeeProtocol()) { 3449 case RAW_802_15_4: 3450 xbeePacket = new TX64Packet(getNextFrameID(), address, XBeeTransmitOptions.NONE, data); 3451 break; 3452 default: 3453 xbeePacket = new TransmitPacket(getNextFrameID(), address, XBee16BitAddress.UNKNOWN_ADDRESS, 0, XBeeTransmitOptions.NONE, data); 3454 } 3455 sendAndCheckXBeePacket(xbeePacket, true); 3456 } 3457 3458 /** 3459 * Sends asynchronously the provided data to the XBee device of the network 3460 * corresponding to the given 64-bit/16-bit address. 3461 * 3462 * <p>Asynchronous transmissions do not wait for answer from the remote 3463 * device or for transmit status packet.</p> 3464 * 3465 * @param address64Bit The 64-bit address of the XBee that will receive the 3466 * data. 3467 * @param address16Bit The 16-bit address of the XBee that will receive the 3468 * data. If it is unknown the 3469 * {@code XBee16BitAddress.UNKNOWN_ADDRESS} must be 3470 * used. 3471 * @param data Byte array containing the data to be sent. 3472 * 3473 * @throws InterfaceNotOpenException if this device connection is not open. 3474 * @throws NullPointerException if {@code address64Bit == null} or 3475 * if {@code address16Bit == null} or 3476 * if {@code data == null}. 3477 * @throws XBeeException if a remote device is trying to send data or 3478 * if there is any other XBee related exception. 3479 * 3480 * @see #sendData(RemoteXBeeDevice, byte[]) 3481 * @see #sendData(XBee64BitAddress, byte[]) 3482 * @see #sendData(XBee64BitAddress, XBee16BitAddress, byte[]) 3483 * @see #sendDataAsync(RemoteXBeeDevice, byte[]) 3484 * @see #sendDataAsync(XBee64BitAddress, byte[]) 3485 * @see com.digi.xbee.api.models.XBee16BitAddress 3486 * @see com.digi.xbee.api.models.XBee64BitAddress 3487 */ 3488 protected void sendDataAsync(XBee64BitAddress address64Bit, XBee16BitAddress address16Bit, byte[] data) throws XBeeException { 3489 // Verify the parameters are not null, if they are null, throw an exception. 3490 if (address64Bit == null) 3491 throw new NullPointerException("64-bit address cannot be null"); 3492 if (address16Bit == null) 3493 throw new NullPointerException("16-bit address cannot be null"); 3494 if (data == null) 3495 throw new NullPointerException("Data cannot be null"); 3496 3497 // Check if device is remote. 3498 if (isRemote()) 3499 throw new OperationNotSupportedException("Cannot send data to a remote device from a remote device."); 3500 3501 logger.debug(toString() + "Sending data asynchronously to {}[{}] >> {}.", 3502 address64Bit, address16Bit, HexUtils.prettyHexString(data)); 3503 3504 XBeePacket xbeePacket = new TransmitPacket(getNextFrameID(), address64Bit, address16Bit, 0, XBeeTransmitOptions.NONE, data); 3505 sendAndCheckXBeePacket(xbeePacket, true); 3506 } 3507 3508 /** 3509 * Sends the provided data to the provided XBee device asynchronously 3510 * choosing the optimal send method depending on the protocol of the local 3511 * XBee device. 3512 * 3513 * <p>Asynchronous transmissions do not wait for answer from the remote 3514 * device or for transmit status packet.</p> 3515 * 3516 * @param remoteXBeeDevice The XBee device of the network that will receive the 3517 * data. 3518 * @param data Byte array containing the data to be sent. 3519 * 3520 * @throws InterfaceNotOpenException if this device connection is not open. 3521 * @throws NullPointerException if {@code remoteXBeeDevice == null} or 3522 * if {@code data == null}. 3523 * @throws XBeeException if there is any XBee related exception. 3524 * 3525 * @see #sendData(RemoteXBeeDevice, byte[]) 3526 * @see #sendData(XBee64BitAddress, byte[]) 3527 * @see #sendData(XBee64BitAddress, XBee16BitAddress, byte[]) 3528 * @see #sendDataAsync(XBee64BitAddress, byte[]) 3529 * @see #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[]) 3530 * @see RemoteXBeeDevice 3531 */ 3532 protected void sendDataAsync(RemoteXBeeDevice remoteXBeeDevice, byte[] data) throws XBeeException { 3533 if (remoteXBeeDevice == null) 3534 throw new NullPointerException("Remote XBee device cannot be null"); 3535 3536 switch (getXBeeProtocol()) { 3537 case ZIGBEE: 3538 case DIGI_POINT: 3539 if (remoteXBeeDevice.get64BitAddress() != null && remoteXBeeDevice.get16BitAddress() != null) 3540 sendDataAsync(remoteXBeeDevice.get64BitAddress(), remoteXBeeDevice.get16BitAddress(), data); 3541 else 3542 sendDataAsync(remoteXBeeDevice.get64BitAddress(), data); 3543 break; 3544 case RAW_802_15_4: 3545 if (this instanceof Raw802Device) { 3546 if (remoteXBeeDevice.get64BitAddress() != null) 3547 ((Raw802Device)this).sendDataAsync(remoteXBeeDevice.get64BitAddress(), data); 3548 else 3549 ((Raw802Device)this).sendDataAsync(remoteXBeeDevice.get16BitAddress(), data); 3550 } else 3551 sendDataAsync(remoteXBeeDevice.get64BitAddress(), data); 3552 break; 3553 case DIGI_MESH: 3554 default: 3555 sendDataAsync(remoteXBeeDevice.get64BitAddress(), data); 3556 } 3557 } 3558 3559 /** 3560 * Sends the provided data to the XBee device of the network corresponding 3561 * to the given 64-bit address. 3562 * 3563 * <p>This method blocks till a success or error response arrives or the 3564 * configured receive timeout expires.</p> 3565 * 3566 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 3567 * method and can be consulted with {@code getReceiveTimeout} method.</p> 3568 * 3569 * <p>For non-blocking operations use the method 3570 * {@link #sendDataAsync(XBee64BitAddress, byte[])}.</p> 3571 * 3572 * @param address The 64-bit address of the XBee that will receive the data. 3573 * @param data Byte array containing the data to be sent. 3574 * 3575 * @throws InterfaceNotOpenException if this device connection is not open. 3576 * @throws NullPointerException if {@code address == null} or 3577 * if {@code data == null}. 3578 * @throws TimeoutException if there is a timeout sending the data. 3579 * @throws XBeeException if there is any other XBee related exception. 3580 * 3581 * @see #getReceiveTimeout() 3582 * @see #setReceiveTimeout(int) 3583 * @see #sendData(RemoteXBeeDevice, byte[]) 3584 * @see #sendData(XBee64BitAddress, XBee16BitAddress, byte[]) 3585 * @see #sendDataAsync(RemoteXBeeDevice, byte[]) 3586 * @see #sendDataAsync(XBee64BitAddress, byte[]) 3587 * @see #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[]) 3588 * @see com.digi.xbee.api.models.XBee64BitAddress 3589 */ 3590 protected void sendData(XBee64BitAddress address, byte[] data) throws TimeoutException, XBeeException { 3591 // Verify the parameters are not null, if they are null, throw an exception. 3592 if (address == null) 3593 throw new NullPointerException("Address cannot be null"); 3594 if (data == null) 3595 throw new NullPointerException("Data cannot be null"); 3596 3597 // Check if device is remote. 3598 if (isRemote()) 3599 throw new OperationNotSupportedException("Cannot send data to a remote device from a remote device."); 3600 3601 logger.debug(toString() + "Sending data to {} >> {}.", address, HexUtils.prettyHexString(data)); 3602 3603 XBeePacket xbeePacket; 3604 switch (getXBeeProtocol()) { 3605 case RAW_802_15_4: 3606 xbeePacket = new TX64Packet(getNextFrameID(), address, XBeeTransmitOptions.NONE, data); 3607 break; 3608 default: 3609 xbeePacket = new TransmitPacket(getNextFrameID(), address, XBee16BitAddress.UNKNOWN_ADDRESS, 0, XBeeTransmitOptions.NONE, data); 3610 } 3611 sendAndCheckXBeePacket(xbeePacket, false); 3612 } 3613 3614 /** 3615 * Sends the provided data to the XBee device of the network corresponding 3616 * to the given 64-bit/16-bit address. 3617 * 3618 * <p>This method blocks till a success or error response arrives or the 3619 * configured receive timeout expires.</p> 3620 * 3621 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 3622 * method and can be consulted with {@code getReceiveTimeout} method.</p> 3623 * 3624 * <p>For non-blocking operations use the method 3625 * {@link #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[])}.</p> 3626 * 3627 * @param address64Bit The 64-bit address of the XBee that will receive the 3628 * data. 3629 * @param address16Bit The 16-bit address of the XBee that will receive the 3630 * data. If it is unknown the 3631 * {@code XBee16BitAddress.UNKNOWN_ADDRESS} must be 3632 * used. 3633 * @param data Byte array containing the data to be sent. 3634 * 3635 * @throws InterfaceNotOpenException if this device connection is not open. 3636 * @throws NullPointerException if {@code address64Bit == null} or 3637 * if {@code address16Bit == null} or 3638 * if {@code data == null}. 3639 * @throws TimeoutException if there is a timeout sending the data. 3640 * @throws XBeeException if a remote device is trying to send data or 3641 * if there is any other XBee related exception. 3642 * 3643 * @see #getReceiveTimeout() 3644 * @see #setReceiveTimeout(int) 3645 * @see #sendData(RemoteXBeeDevice, byte[]) 3646 * @see #sendData(XBee64BitAddress, byte[]) 3647 * @see #sendDataAsync(RemoteXBeeDevice, byte[]) 3648 * @see #sendDataAsync(XBee64BitAddress, byte[]) 3649 * @see #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[]) 3650 * @see com.digi.xbee.api.models.XBee16BitAddress 3651 * @see com.digi.xbee.api.models.XBee64BitAddress 3652 */ 3653 protected void sendData(XBee64BitAddress address64Bit, XBee16BitAddress address16Bit, byte[] data) throws TimeoutException, XBeeException { 3654 // Verify the parameters are not null, if they are null, throw an exception. 3655 if (address64Bit == null) 3656 throw new NullPointerException("64-bit address cannot be null"); 3657 if (address16Bit == null) 3658 throw new NullPointerException("16-bit address cannot be null"); 3659 if (data == null) 3660 throw new NullPointerException("Data cannot be null"); 3661 3662 // Check if device is remote. 3663 if (isRemote()) 3664 throw new OperationNotSupportedException("Cannot send data to a remote device from a remote device."); 3665 3666 logger.debug(toString() + "Sending data to {}[{}] >> {}.", 3667 address64Bit, address16Bit, HexUtils.prettyHexString(data)); 3668 3669 XBeePacket xbeePacket = new TransmitPacket(getNextFrameID(), address64Bit, address16Bit, 0, XBeeTransmitOptions.NONE, data); 3670 sendAndCheckXBeePacket(xbeePacket, false); 3671 } 3672 3673 /** 3674 * Sends the provided data to the given XBee device choosing the optimal 3675 * send method depending on the protocol of the local XBee device. 3676 * 3677 * <p>This method blocks till a success or error response arrives or the 3678 * configured receive timeout expires.</p> 3679 * 3680 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 3681 * method and can be consulted with {@code getReceiveTimeout} method.</p> 3682 * 3683 * <p>For non-blocking operations use the method 3684 * {@link #sendDataAsync(RemoteXBeeDevice, byte[])}.</p> 3685 * 3686 * @param remoteXBeeDevice The XBee device of the network that will receive 3687 * the data. 3688 * @param data Byte array containing the data to be sent. 3689 * 3690 * @throws InterfaceNotOpenException if this device connection is not open. 3691 * @throws NullPointerException if {@code xbeeDevice == null} or 3692 * if {@code data == null}. 3693 * @throws TimeoutException if there is a timeout sending the data. 3694 * @throws XBeeException if there is any other XBee related exception. 3695 * 3696 * @see #getReceiveTimeout() 3697 * @see #setReceiveTimeout(int) 3698 * @see #sendData(XBee64BitAddress, byte[]) 3699 * @see #sendData(XBee64BitAddress, XBee16BitAddress, byte[]) 3700 * @see #sendDataAsync(RemoteXBeeDevice, byte[]) 3701 * @see #sendDataAsync(XBee64BitAddress, byte[]) 3702 * @see #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[]) 3703 * @see com.digi.xbee.api.RemoteXBeeDevice 3704 */ 3705 protected void sendData(RemoteXBeeDevice remoteXBeeDevice, byte[] data) throws TimeoutException, XBeeException { 3706 if (remoteXBeeDevice == null) 3707 throw new NullPointerException("Remote XBee device cannot be null"); 3708 3709 switch (getXBeeProtocol()) { 3710 case ZIGBEE: 3711 case DIGI_POINT: 3712 if (remoteXBeeDevice.get64BitAddress() != null && remoteXBeeDevice.get16BitAddress() != null) 3713 sendData(remoteXBeeDevice.get64BitAddress(), remoteXBeeDevice.get16BitAddress(), data); 3714 else 3715 sendData(remoteXBeeDevice.get64BitAddress(), data); 3716 break; 3717 case RAW_802_15_4: 3718 if (this instanceof Raw802Device) { 3719 if (remoteXBeeDevice.get64BitAddress() != null) 3720 ((Raw802Device)this).sendData(remoteXBeeDevice.get64BitAddress(), data); 3721 else 3722 ((Raw802Device)this).sendData(remoteXBeeDevice.get16BitAddress(), data); 3723 } else 3724 sendData(remoteXBeeDevice.get64BitAddress(), data); 3725 break; 3726 case DIGI_MESH: 3727 default: 3728 sendData(remoteXBeeDevice.get64BitAddress(), data); 3729 } 3730 } 3731 3732 /** 3733 * Sends the provided data to all the XBee nodes of the network (broadcast). 3734 * 3735 * <p>This method blocks till a success or error transmit status arrives or 3736 * the configured receive timeout expires.</p> 3737 * 3738 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 3739 * method and can be consulted with {@code getReceiveTimeout} method.</p> 3740 * 3741 * @param data Byte array containing the data to be sent. 3742 * 3743 * @throws InterfaceNotOpenException if this device connection is not open. 3744 * @throws NullPointerException if {@code data == null}. 3745 * @throws TimeoutException if there is a timeout sending the data. 3746 * @throws XBeeException if there is any other XBee related exception. 3747 * 3748 * @see #getReceiveTimeout() 3749 * @see #setReceiveTimeout(int) 3750 */ 3751 protected void sendBroadcastData(byte[] data) throws TimeoutException, XBeeException { 3752 sendData(XBee64BitAddress.BROADCAST_ADDRESS, data); 3753 } 3754 3755 /** 3756 * Sends asynchronously the provided data in application layer mode to the 3757 * XBee device of the network corresponding to the given 64-bit address. 3758 * Application layer mode means that you need to specify the application 3759 * layer fields to be sent with the data. 3760 * 3761 * <p>Asynchronous transmissions do not wait for answer from the remote 3762 * device or for transmit status packet.</p> 3763 * 3764 * @param address The 64-bit address of the XBee that will receive the data. 3765 * @param sourceEndpoint Source endpoint for the transmission. 3766 * @param destEndpoint Destination endpoint for the transmission. 3767 * @param clusterID Cluster ID used in the transmission. 3768 * @param profileID Profile ID used in the transmission. 3769 * @param data Byte array containing the data to be sent. 3770 * 3771 * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 3772 * if {@code sourceEndpoint > 0xFF} or 3773 * if {@code destEndpoint < 0} or 3774 * if {@code destEndpoint > 0xFF} or 3775 * if {@code clusterID < 0} or 3776 * if {@code clusterID > 0xFFFF} or 3777 * if {@code profileID < 0} or 3778 * if {@code profileID > 0xFFFF}. 3779 * @throws InterfaceNotOpenException if this device connection is not open. 3780 * @throws NullPointerException if {@code address == null} or 3781 * if {@code data == null}. 3782 * @throws XBeeException if there is any other XBee related exception. 3783 * 3784 * @see #sendExplicitData(RemoteXBeeDevice, int, int, int, int, byte[]) 3785 * @see #sendExplicitData(XBee64BitAddress, int, int, int, int, byte[]) 3786 * @see #sendExplicitData(XBee64BitAddress, XBee16BitAddress, int, int, int, int, byte[]) 3787 * @see #sendExplicitDataAsync(RemoteXBeeDevice, int, int, int, int, byte[]) 3788 * @see #sendExplicitDataAsync(XBee64BitAddress, XBee16BitAddress, int, int, int, int, byte[]) 3789 * @see com.digi.xbee.api.models.XBee64BitAddress 3790 */ 3791 protected void sendExplicitDataAsync(XBee64BitAddress address, int sourceEndpoint, int destEndpoint, int clusterID, 3792 int profileID, byte[] data) throws XBeeException { 3793 if (address == null) 3794 throw new NullPointerException("Address cannot be null"); 3795 if (data == null) 3796 throw new NullPointerException("Data cannot be null."); 3797 if (sourceEndpoint < 0 || sourceEndpoint > 0xFF) 3798 throw new IllegalArgumentException("Source endpoint must be between 0 and 0xFF."); 3799 if (destEndpoint < 0 || destEndpoint > 0xFF) 3800 throw new IllegalArgumentException("Destination endpoint must be between 0 and 0xFF."); 3801 if (clusterID < 0 || clusterID > 0xFFFF) 3802 throw new IllegalArgumentException("Cluster ID must be between 0 and 0xFFFF."); 3803 if (profileID < 0 || profileID > 0xFFFF) 3804 throw new IllegalArgumentException("Profile ID must be between 0 and 0xFFFF."); 3805 3806 // Check if device is remote. 3807 if (isRemote()) 3808 throw new OperationNotSupportedException("Cannot send explicit data to a remote device from a remote device."); 3809 3810 logger.debug(toString() + "Sending explicit data asynchronously to {} [{} - {} - {} - {}] >> {}.", address, 3811 String.format("%02X", sourceEndpoint), String.format("%02X", destEndpoint), 3812 String.format("%04X", clusterID), String.format("%04X", profileID), 3813 HexUtils.prettyHexString(data)); 3814 3815 XBeePacket xbeePacket = new ExplicitAddressingPacket(getNextFrameID(), address, XBee16BitAddress.UNKNOWN_ADDRESS, sourceEndpoint, destEndpoint, clusterID, profileID, 0, XBeeTransmitOptions.NONE, data); 3816 sendAndCheckXBeePacket(xbeePacket, true); 3817 } 3818 3819 /** 3820 * Sends asynchronously the provided data in application layer mode to the 3821 * XBee device of the network corresponding to the given 64-bit/16-bit 3822 * address. Application layer mode means that you need to specify the 3823 * application layer fields to be sent with the data. 3824 * 3825 * <p>Asynchronous transmissions do not wait for answer from the remote 3826 * device or for transmit status packet.</p> 3827 * 3828 * @param address64Bit The 64-bit address of the XBee that will receive the 3829 * data. 3830 * @param address16Bit The 16-bit address of the XBee that will receive the 3831 * data. If it is unknown the 3832 * {@code XBee16BitAddress.UNKNOWN_ADDRESS} must be 3833 * used. 3834 * @param sourceEndpoint Source endpoint for the transmission. 3835 * @param destEndpoint Destination endpoint for the transmission. 3836 * @param clusterID Cluster ID used in the transmission. 3837 * @param profileID Profile ID used in the transmission. 3838 * @param data Byte array containing the data to be sent. 3839 * 3840 * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 3841 * if {@code sourceEndpoint > 0xFF} or 3842 * if {@code destEndpoint < 0} or 3843 * if {@code destEndpoint > 0xFF} or 3844 * if {@code clusterID < 0} or 3845 * if {@code clusterID > 0xFFFF} or 3846 * if {@code profileID < 0} or 3847 * if {@code profileID > 0xFFFF}. 3848 * @throws InterfaceNotOpenException if this device connection is not open. 3849 * @throws NullPointerException if {@code address64Bit == null} or 3850 * if {@code address16Bit == null} or 3851 * if {@code data == null}. 3852 * @throws XBeeException if there is any other XBee related exception. 3853 * 3854 * @see #sendExplicitData(RemoteXBeeDevice, int, int, int, int, byte[]) 3855 * @see #sendExplicitData(XBee64BitAddress, int, int, int, int, byte[]) 3856 * @see #sendExplicitData(XBee64BitAddress, XBee16BitAddress, int, int, int, int, byte[]) 3857 * @see #sendExplicitDataAsync(RemoteXBeeDevice, int, int, int, int, byte[]) 3858 * @see #sendExplicitDataAsync(XBee64BitAddress, int, int, int, int, byte[]) 3859 * @see com.digi.xbee.api.models.XBee16BitAddress 3860 * @see com.digi.xbee.api.models.XBee64BitAddress 3861 */ 3862 protected void sendExplicitDataAsync(XBee64BitAddress address64Bit, XBee16BitAddress address16Bit, int sourceEndpoint, 3863 int destEndpoint, int clusterID, int profileID, byte[] data) throws XBeeException { 3864 if (address64Bit == null) 3865 throw new NullPointerException("64-bit address cannot be null."); 3866 if (address16Bit == null) 3867 throw new NullPointerException("16-bit address cannot be null."); 3868 if (data == null) 3869 throw new NullPointerException("Data cannot be null."); 3870 if (sourceEndpoint < 0 || sourceEndpoint > 0xFF) 3871 throw new IllegalArgumentException("Source endpoint must be between 0 and 0xFF."); 3872 if (destEndpoint < 0 || destEndpoint > 0xFF) 3873 throw new IllegalArgumentException("Destination endpoint must be between 0 and 0xFF."); 3874 if (clusterID < 0 || clusterID > 0xFFFF) 3875 throw new IllegalArgumentException("Cluster ID must be between 0 and 0xFFFF."); 3876 if (profileID < 0 || profileID > 0xFFFF) 3877 throw new IllegalArgumentException("Profile ID must be between 0 and 0xFFFF."); 3878 3879 // Check if device is remote. 3880 if (isRemote()) 3881 throw new OperationNotSupportedException("Cannot send explicit data to a remote device from a remote device."); 3882 3883 logger.debug(toString() + "Sending explicit data asynchronously to {}[{}] [{} - {} - {} - {}] >> {}.", address64Bit, address16Bit, 3884 String.format("%02X", sourceEndpoint), String.format("%02X", destEndpoint), 3885 String.format("%04X", clusterID), String.format("%04X", profileID), 3886 HexUtils.prettyHexString(data)); 3887 3888 XBeePacket xbeePacket = new ExplicitAddressingPacket(getNextFrameID(), address64Bit, address16Bit, sourceEndpoint, destEndpoint, clusterID, profileID, 0, XBeeTransmitOptions.NONE, data); 3889 sendAndCheckXBeePacket(xbeePacket, true); 3890 } 3891 3892 /** 3893 * Sends asynchronously the provided data in application layer mode to the 3894 * provided XBee device choosing the optimal send method depending on the 3895 * protocol of the local XBee device. Application layer mode means that you 3896 * need to specify the application layer fields to be sent with the data. 3897 * 3898 * <p>Asynchronous transmissions do not wait for answer from the remote 3899 * device or for transmit status packet.</p> 3900 * 3901 * @param remoteXBeeDevice The XBee device of the network that will receive 3902 * the data. 3903 * @param sourceEndpoint Source endpoint for the transmission. 3904 * @param destEndpoint Destination endpoint for the transmission. 3905 * @param clusterID Cluster ID used in the transmission. 3906 * @param profileID Profile ID used in the transmission. 3907 * @param data Byte array containing the data to be sent. 3908 * 3909 * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 3910 * if {@code sourceEndpoint > 0xFF} or 3911 * if {@code destEndpoint < 0} or 3912 * if {@code destEndpoint > 0xFF} or 3913 * if {@code clusterID < 0} or 3914 * if {@code clusterID > 0xFFFF} or 3915 * if {@code profileID < 0} or 3916 * if {@code profileID > 0xFFFF}. 3917 * @throws InterfaceNotOpenException if this device connection is not open. 3918 * @throws NullPointerException if {@code remoteXBeeDevice == null} or 3919 * if {@code data == null}. 3920 * @throws XBeeException if there is any other XBee related exception. 3921 * 3922 * @see #sendExplicitData(RemoteXBeeDevice, int, int, int, int, byte[]) 3923 * @see #sendExplicitData(XBee64BitAddress, int, int, int, int, byte[]) 3924 * @see #sendExplicitData(XBee64BitAddress, XBee16BitAddress, int, int, int, int, byte[]) 3925 * @see #sendExplicitDataAsync(XBee64BitAddress, int, int, int, int, byte[]) 3926 * @see #sendExplicitDataAsync(XBee64BitAddress, XBee16BitAddress, int, int, int, int, byte[]) 3927 * @see RemoteXBeeDevice 3928 */ 3929 protected void sendExplicitDataAsync(RemoteXBeeDevice remoteXBeeDevice, int sourceEndpoint, int destEndpoint, 3930 int clusterID, int profileID, byte[] data) throws XBeeException { 3931 if (remoteXBeeDevice == null) 3932 throw new NullPointerException("Remote XBee device cannot be null"); 3933 3934 switch (getXBeeProtocol()) { 3935 case ZIGBEE: 3936 case DIGI_POINT: 3937 if (remoteXBeeDevice.get64BitAddress() != null && remoteXBeeDevice.get16BitAddress() != null) 3938 sendExplicitDataAsync(remoteXBeeDevice.get64BitAddress(), remoteXBeeDevice.get16BitAddress(), sourceEndpoint, destEndpoint, clusterID, profileID, data); 3939 else 3940 sendExplicitDataAsync(remoteXBeeDevice.get64BitAddress(), sourceEndpoint, destEndpoint, clusterID, profileID, data); 3941 break; 3942 case RAW_802_15_4: 3943 throw new OperationNotSupportedException("802.15.4. protocol does not support explicit data transmissions."); 3944 case DIGI_MESH: 3945 default: 3946 sendExplicitDataAsync(remoteXBeeDevice.get64BitAddress(), sourceEndpoint, destEndpoint, clusterID, profileID, data); 3947 } 3948 } 3949 3950 /** 3951 * Sends the provided data in application layer mode to the XBee device of 3952 * the network corresponding to the given 64-bit address. Application layer 3953 * mode means that you need to specify the application layer fields to be 3954 * sent with the data. 3955 * 3956 * <p>This method blocks till a success or error response arrives or the 3957 * configured receive timeout expires.</p> 3958 * 3959 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 3960 * method and can be consulted with {@code getReceiveTimeout} method.</p> 3961 * 3962 * @param address The 64-bit address of the XBee that will receive the data. 3963 * @param sourceEndpoint Source endpoint for the transmission. 3964 * @param destEndpoint Destination endpoint for the transmission. 3965 * @param clusterID Cluster ID used in the transmission. 3966 * @param profileID Profile ID used in the transmission. 3967 * @param data Byte array containing the data to be sent. 3968 * 3969 * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 3970 * if {@code sourceEndpoint > 0xFF} or 3971 * if {@code destEndpoint < 0} or 3972 * if {@code destEndpoint > 0xFF} or 3973 * if {@code clusterID < 0} or 3974 * if {@code clusterID > 0xFFFF} or 3975 * if {@code profileID < 0} or 3976 * if {@code profileID > 0xFFFF}. 3977 * @throws InterfaceNotOpenException if this device connection is not open. 3978 * @throws NullPointerException if {@code address == null} or 3979 * if {@code data == null}. 3980 * @throws TimeoutException if there is a timeout sending the data. 3981 * @throws XBeeException if there is any other XBee related exception. 3982 * 3983 * @see #getReceiveTimeout() 3984 * @see #sendExplicitData(RemoteXBeeDevice, int, int, int, int, byte[]) 3985 * @see #sendExplicitData(XBee64BitAddress, XBee16BitAddress, int, int, int, int, byte[]) 3986 * @see #setReceiveTimeout(int) 3987 * @see com.digi.xbee.api.models.XBee64BitAddress 3988 */ 3989 protected void sendExplicitData(XBee64BitAddress address, int sourceEndpoint, int destEndpoint, int clusterID, 3990 int profileID, byte[] data) throws TimeoutException, XBeeException { 3991 if (address == null) 3992 throw new NullPointerException("Address cannot be null"); 3993 if (data == null) 3994 throw new NullPointerException("Data cannot be null."); 3995 if (sourceEndpoint < 0 || sourceEndpoint > 0xFF) 3996 throw new IllegalArgumentException("Source endpoint must be between 0 and 0xFF."); 3997 if (destEndpoint < 0 || destEndpoint > 0xFF) 3998 throw new IllegalArgumentException("Destination endpoint must be between 0 and 0xFF."); 3999 if (clusterID < 0 || clusterID > 0xFFFF) 4000 throw new IllegalArgumentException("Cluster ID must be between 0 and 0xFFFF."); 4001 if (profileID < 0 || profileID > 0xFFFF) 4002 throw new IllegalArgumentException("Profile ID must be between 0 and 0xFFFF."); 4003 4004 // Check if device is remote. 4005 if (isRemote()) 4006 throw new OperationNotSupportedException("Cannot send explicit data to a remote device from a remote device."); 4007 4008 logger.debug(toString() + "Sending explicit data to {} [{} - {} - {} - {}] >> {}.", address, 4009 String.format("%02X", sourceEndpoint), String.format("%02X", destEndpoint), 4010 String.format("%04X", clusterID), String.format("%04X", profileID), 4011 HexUtils.prettyHexString(data)); 4012 4013 XBeePacket xbeePacket = new ExplicitAddressingPacket(getNextFrameID(), address, XBee16BitAddress.UNKNOWN_ADDRESS, sourceEndpoint, destEndpoint, clusterID, profileID, 0, XBeeTransmitOptions.NONE, data); 4014 sendAndCheckXBeePacket(xbeePacket, false); 4015 } 4016 4017 /** 4018 * Sends the provided data in application layer mode to the XBee device of 4019 * the network corresponding to the given 64-bit/16-bit address. 4020 * Application layer mode means that you need to specify the application 4021 * layer fields to be sent with the data. 4022 * 4023 * <p>This method blocks till a success or error response arrives or the 4024 * configured receive timeout expires.</p> 4025 * 4026 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 4027 * method and can be consulted with {@code getReceiveTimeout} method.</p> 4028 * 4029 * @param address64Bit The 64-bit address of the XBee that will receive the 4030 * data. 4031 * @param address16Bit The 16-bit address of the XBee that will receive the 4032 * data. If it is unknown the 4033 * {@code XBee16BitAddress.UNKNOWN_ADDRESS} must be 4034 * used. 4035 * @param sourceEndpoint Source endpoint for the transmission. 4036 * @param destEndpoint Destination endpoint for the transmission. 4037 * @param clusterID Cluster ID used in the transmission. 4038 * @param profileID Profile ID used in the transmission. 4039 * @param data Byte array containing the data to be sent. 4040 * 4041 * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 4042 * if {@code sourceEndpoint > 0xFF} or 4043 * if {@code destEndpoint < 0} or 4044 * if {@code destEndpoint > 0xFF} or 4045 * if {@code clusterID < 0} or 4046 * if {@code clusterID > 0xFFFF} or 4047 * if {@code profileID < 0} or 4048 * if {@code profileID > 0xFFFF}. 4049 * @throws InterfaceNotOpenException if this device connection is not open. 4050 * @throws NullPointerException if {@code address == null} or 4051 * if {@code data == null}. 4052 * @throws TimeoutException if there is a timeout sending the data. 4053 * @throws XBeeException if there is any other XBee related exception. 4054 * 4055 * @see #getReceiveTimeout() 4056 * @see #sendExplicitData(RemoteXBeeDevice, int, int, int, int, byte[]) 4057 * @see #sendExplicitData(XBee64BitAddress, int, int, int, int, byte[]) 4058 * @see #setReceiveTimeout(int) 4059 * @see com.digi.xbee.api.models.XBee16BitAddress 4060 * @see com.digi.xbee.api.models.XBee64BitAddress 4061 */ 4062 protected void sendExplicitData(XBee64BitAddress address64Bit, XBee16BitAddress address16Bit, int sourceEndpoint, int destEndpoint, 4063 int clusterID, int profileID, byte[] data) throws TimeoutException, XBeeException { 4064 // Verify the parameters are not null, if they are null, throw an exception. 4065 if (address64Bit == null) 4066 throw new NullPointerException("64-bit address cannot be null"); 4067 if (address16Bit == null) 4068 throw new NullPointerException("16-bit address cannot be null"); 4069 if (data == null) 4070 throw new NullPointerException("Data cannot be null."); 4071 if (sourceEndpoint < 0 || sourceEndpoint > 0xFF) 4072 throw new IllegalArgumentException("Source endpoint must be between 0 and 0xFF."); 4073 if (destEndpoint < 0 || destEndpoint > 0xFF) 4074 throw new IllegalArgumentException("Destination endpoint must be between 0 and 0xFF."); 4075 if (clusterID < 0 || clusterID > 0xFFFF) 4076 throw new IllegalArgumentException("Cluster ID must be between 0 and 0xFFFF."); 4077 if (profileID < 0 || profileID > 0xFFFF) 4078 throw new IllegalArgumentException("Profile ID must be between 0 and 0xFFFF."); 4079 4080 // Check if device is remote. 4081 if (isRemote()) 4082 throw new OperationNotSupportedException("Cannot send explicit data to a remote device from a remote device."); 4083 4084 logger.debug(toString() + "Sending explicit data to {}[{}] [{} - {} - {} - {}] >> {}.", address64Bit, address16Bit, 4085 String.format("%02X", sourceEndpoint), String.format("%02X", destEndpoint), 4086 String.format("%04X", clusterID), String.format("%04X", profileID), 4087 HexUtils.prettyHexString(data)); 4088 4089 XBeePacket xbeePacket = new ExplicitAddressingPacket(getNextFrameID(), address64Bit, address16Bit, sourceEndpoint, destEndpoint, clusterID, profileID, 0, XBeeTransmitOptions.NONE, data); 4090 sendAndCheckXBeePacket(xbeePacket, false); 4091 } 4092 4093 /** 4094 * Sends the provided data to the given XBee device in application layer 4095 * mode choosing the optimal send method depending on the protocol of the 4096 * local XBee device. Application layer mode means that you need to specify 4097 * the application layer fields to be sent with the data. 4098 * 4099 * <p>This method blocks till a success or error response arrives or the 4100 * configured receive timeout expires.</p> 4101 * 4102 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 4103 * method and can be consulted with {@code getReceiveTimeout} method.</p> 4104 * 4105 * @param remoteXBeeDevice The XBee device of the network that will receive 4106 * the explicit data. 4107 * @param sourceEndpoint Source endpoint for the transmission. 4108 * @param destEndpoint Destination endpoint for the transmission. 4109 * @param clusterID Cluster ID used in the transmission. 4110 * @param profileID Profile ID used in the transmission. 4111 * @param data Byte array containing the data to be sent. 4112 * 4113 * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 4114 * if {@code sourceEndpoint > 0xFF} or 4115 * if {@code destEndpoint < 0} or 4116 * if {@code destEndpoint > 0xFF} or 4117 * if {@code clusterID < 0} or 4118 * if {@code clusterID > 0xFFFF} or 4119 * if {@code profileID < 0} or 4120 * if {@code profileID > 0xFFFF}. 4121 * @throws InterfaceNotOpenException if this device connection is not open. 4122 * @throws NullPointerException if {@code remoteXBeeDevice == null} or 4123 * if {@code data == null}. 4124 * @throws TimeoutException if there is a timeout sending the data. 4125 * @throws XBeeException if there is any other XBee related exception. 4126 * 4127 * @see #getReceiveTimeout() 4128 * @see #sendExplicitData(XBee64BitAddress, int, int, int, int, byte[]) 4129 * @see #sendExplicitData(XBee64BitAddress, XBee16BitAddress, int, int, int, int, byte[]) 4130 * @see #setReceiveTimeout(int) 4131 * @see com.digi.xbee.api.RemoteXBeeDevice 4132 */ 4133 protected void sendExplicitData(RemoteXBeeDevice remoteXBeeDevice, int sourceEndpoint, int destEndpoint, int clusterID, 4134 int profileID, byte[] data) throws TimeoutException, XBeeException { 4135 if (remoteXBeeDevice == null) 4136 throw new NullPointerException("Remote XBee device cannot be null."); 4137 4138 switch (getXBeeProtocol()) { 4139 case ZIGBEE: 4140 case DIGI_POINT: 4141 if (remoteXBeeDevice.get64BitAddress() != null && remoteXBeeDevice.get16BitAddress() != null) 4142 sendExplicitData(remoteXBeeDevice.get64BitAddress(), remoteXBeeDevice.get16BitAddress(), sourceEndpoint, destEndpoint, clusterID, profileID, data); 4143 else 4144 sendExplicitData(remoteXBeeDevice.get64BitAddress(), sourceEndpoint, destEndpoint, clusterID, profileID, data); 4145 break; 4146 case RAW_802_15_4: 4147 throw new OperationNotSupportedException("802.15.4. protocol does not support explicit data transmissions."); 4148 case DIGI_MESH: 4149 default: 4150 sendExplicitData(remoteXBeeDevice.get64BitAddress(), sourceEndpoint, destEndpoint, clusterID, profileID, data); 4151 } 4152 } 4153 4154 /** 4155 * Sends the provided data to all the XBee nodes of the network (broadcast) 4156 * in application layer mode. Application layer mode means that you need to 4157 * specify the application layer fields to be sent with the data. 4158 * 4159 * <p>This method blocks till a success or error transmit status arrives or 4160 * the configured receive timeout expires.</p> 4161 * 4162 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 4163 * method and can be consulted with {@code getReceiveTimeout} method.</p> 4164 * 4165 * @param sourceEndpoint Source endpoint for the transmission. 4166 * @param destEndpoint Destination endpoint for the transmission. 4167 * @param clusterID Cluster ID used in the transmission. 4168 * @param profileID Profile ID used in the transmission. 4169 * @param data Byte array containing the data to be sent. 4170 * 4171 * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 4172 * if {@code sourceEndpoint > 0xFF} or 4173 * if {@code destEndpoint < 0} or 4174 * if {@code destEndpoint > 0xFF} or 4175 * if {@code clusterID < 0} or 4176 * if {@code clusterID > 0xFFFF} or 4177 * if {@code profileID < 0} or 4178 * if {@code profileID > 0xFFFF}. 4179 * @throws InterfaceNotOpenException if this device connection is not open. 4180 * @throws NullPointerException if {@code remoteXBeeDevice == null} or 4181 * if {@code data == null}. 4182 * @throws TimeoutException if there is a timeout sending the data. 4183 * @throws XBeeException if there is any other XBee related exception. 4184 * 4185 * @see #getReceiveTimeout() 4186 * @see #setReceiveTimeout(int) 4187 */ 4188 protected void sendBroadcastExplicitData(int sourceEndpoint, int destEndpoint, int clusterID, int profileID, 4189 byte[] data) throws TimeoutException, XBeeException { 4190 if (getXBeeProtocol() == XBeeProtocol.RAW_802_15_4) 4191 throw new OperationNotSupportedException("802.15.4. protocol does not support explicit data transmissions."); 4192 4193 sendExplicitData(XBee64BitAddress.BROADCAST_ADDRESS, sourceEndpoint, destEndpoint, clusterID, profileID, data); 4194 } 4195 4196 /** 4197 * Sends the given data to the given XBee local interface. 4198 * 4199 * @param destInterface Destination XBee local interface. 4200 * @param data Data to send. 4201 * 4202 * @throws InterfaceNotOpenException if this device connection is not open. 4203 * @throws NullPointerException if {@code destInterface == null}. 4204 * @throws XBeeException if there is any XBee related exception sending the 4205 * User Data Relay message. 4206 * 4207 * @see XBeeLocalInterface 4208 * 4209 * @since 1.3.0 4210 */ 4211 protected void sendUserDataRelay(XBeeLocalInterface destInterface, byte[] data) throws XBeeException { 4212 if (destInterface == null) 4213 throw new NullPointerException("Destination interface cannot be null."); 4214 4215 // Check if device is remote. 4216 if (isRemote()) 4217 throw new OperationNotSupportedException("Cannot send User Data Relay messages from a remote device."); 4218 4219 logger.debug(toString() + "Sending User Data Relay to {} >> {}.", destInterface.getDescription(), 4220 data != null ? HexUtils.prettyHexString(data) : ""); 4221 4222 XBeePacket xbeePacket = new UserDataRelayPacket(getNextFrameID(), destInterface, data); 4223 // Send the packet asynchronously since User Data Relay frames do not receive any transmit status. 4224 sendAndCheckXBeePacket(xbeePacket, true); 4225 } 4226 4227 /** 4228 * Sends the given data to the XBee Bluetooth interface in a User Data Relay 4229 * frame. 4230 * 4231 * @param data Data to send. 4232 * 4233 * @throws InterfaceNotOpenException if this device connection is not open. 4234 * @throws XBeeException if there is any XBee related exception sending the 4235 * data. 4236 * 4237 * @see #sendMicroPythonData(byte[]) 4238 * @see #sendUserDataRelay(XBeeLocalInterface, byte[]) 4239 * 4240 * @since 1.3.0 4241 */ 4242 protected void sendBluetoothData(byte[] data) throws XBeeException { 4243 sendUserDataRelay(XBeeLocalInterface.BLUETOOTH, data); 4244 } 4245 4246 /** 4247 * Sends the given data to the XBee MicroPython interface in a User Data 4248 * Relay frame. 4249 * 4250 * @param data Data to send. 4251 * 4252 * @throws InterfaceNotOpenException if this device connection is not open. 4253 * @throws XBeeException if there is any XBee related exception sending the 4254 * data. 4255 * 4256 * @see #sendBluetoothData(byte[]) 4257 * @see #sendUserDataRelay(XBeeLocalInterface, byte[]) 4258 * 4259 * @since 1.3.0 4260 */ 4261 protected void sendMicroPythonData(byte[] data) throws XBeeException { 4262 sendUserDataRelay(XBeeLocalInterface.MICROPYTHON, data); 4263 } 4264 4265 /** 4266 * Sends the given data to the XBee serial interface in a User Data Relay 4267 * frame. 4268 * 4269 * @param data Data to send. 4270 * 4271 * @throws InterfaceNotOpenException if this device connection is not open. 4272 * @throws XBeeException if there is any XBee related exception sending the 4273 * data. 4274 * 4275 * @see #sendBluetoothData(byte[]) 4276 * @see #sendMicroPythonData(byte[]) 4277 * @see #sendUserDataRelay(XBeeLocalInterface, byte[]) 4278 * 4279 * @since 1.3.0 4280 */ 4281 protected void sendSerialData(byte[] data) throws XBeeException { 4282 sendUserDataRelay(XBeeLocalInterface.SERIAL, data); 4283 } 4284 4285 /** 4286 * Sends the given XBee packet and registers the given packet listener 4287 * (if not {@code null}) to be notified when the answers is received. 4288 * 4289 * <p>This is a non-blocking operation. To wait for the answer use 4290 * {@code sendPacket(XBeePacket)}.</p> 4291 * 4292 * @param packet XBee packet to be sent. 4293 * @param packetReceiveListener Listener for the operation, {@code null} 4294 * not to be notified when the answer arrives. 4295 * 4296 * @throws InterfaceNotOpenException if this device connection is not open. 4297 * @throws NullPointerException if {@code packet == null}. 4298 * @throws XBeeException if there is any other XBee related exception. 4299 * 4300 * @see #sendPacket(XBeePacket) 4301 * @see #sendPacketAsync(XBeePacket) 4302 * @see com.digi.xbee.api.listeners.IPacketReceiveListener 4303 * @see com.digi.xbee.api.packet.XBeePacket 4304 */ 4305 protected void sendPacket(XBeePacket packet, IPacketReceiveListener packetReceiveListener) throws XBeeException { 4306 try { 4307 sendXBeePacket(packet, packetReceiveListener); 4308 } catch (IOException e) { 4309 throw new XBeeException("Error writing in the communication interface.", e); 4310 } 4311 } 4312 4313 /** 4314 * Sends the given XBee packet asynchronously. 4315 * 4316 * <p>This is a non-blocking operation that do not wait for the answer and 4317 * is never notified when it arrives.</p> 4318 * 4319 * <p>To be notified when the answer is received, use 4320 * {@link #sendXBeePacket(XBeePacket, IPacketReceiveListener)}.</p> 4321 * 4322 * @param packet XBee packet to be sent asynchronously. 4323 * 4324 * @throws InterfaceNotOpenException if this device connection is not open. 4325 * @throws NullPointerException if {@code packet == null}. 4326 * @throws XBeeException if there is any other XBee related exception. 4327 * 4328 * @see #sendXBeePacket(XBeePacket) 4329 * @see #sendXBeePacket(XBeePacket, IPacketReceiveListener) 4330 * @see com.digi.xbee.api.packet.XBeePacket 4331 */ 4332 protected void sendPacketAsync(XBeePacket packet) throws XBeeException { 4333 try { 4334 sendXBeePacket(packet, null); 4335 } catch (IOException e) { 4336 throw new XBeeException("Error writing in the communication interface.", e); 4337 } 4338 } 4339 4340 /** 4341 * Sends the given XBee packet synchronously and blocks until the response 4342 * is received or the configured receive timeout expires. 4343 * 4344 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 4345 * method and can be consulted with {@code getReceiveTimeout} method.</p> 4346 * 4347 * <p>Use {@code sendXBeePacketAsync(XBeePacket)} or 4348 * {@code #sendXBeePacket(XBeePacket, IPacketReceiveListener)} for 4349 * non-blocking operations.</p> 4350 * 4351 * @param packet XBee packet to be sent. 4352 * 4353 * @return An {@code XBeePacket} object containing the response of the sent 4354 * packet or {@code null} if there is no response. 4355 * 4356 * @throws InterfaceNotOpenException if this device connection is not open. 4357 * @throws NullPointerException if {@code packet == null}. 4358 * @throws TimeoutException if there is a timeout sending the XBee packet. 4359 * @throws XBeeException if there is any other XBee related exception. 4360 * 4361 * @see #getReceiveTimeout() 4362 * @see #sendXBeePacket(XBeePacket, IPacketReceiveListener) 4363 * @see #sendXBeePacketAsync(XBeePacket) 4364 * @see #setReceiveTimeout(int) 4365 * @see com.digi.xbee.api.packet.XBeePacket 4366 */ 4367 protected XBeePacket sendPacket(XBeePacket packet) throws TimeoutException, XBeeException { 4368 try { 4369 return sendXBeePacket(packet); 4370 } catch (IOException e) { 4371 throw new XBeeException("Error writing in the communication interface.", e); 4372 } 4373 } 4374 4375 /** 4376 * Waits until a Modem Status packet with a reset status, 4377 * {@code ModemStatusEvent.STATUS_HARDWARE_RESET} (0x00), or a watchdog 4378 * timer reset, {@code ModemStatusEvent.STATUS_WATCHDOG_TIMER_RESET} (0x01), 4379 * is received or the timeout expires. 4380 * 4381 * @return {@code true} if the Modem Status packet is received, 4382 * {@code false} otherwise. 4383 * 4384 * @see com.digi.xbee.api.models.ModemStatusEvent#STATUS_HARDWARE_RESET 4385 * @see com.digi.xbee.api.models.ModemStatusEvent#STATUS_WATCHDOG_TIMER_RESET 4386 */ 4387 private boolean waitForModemResetStatusPacket() { 4388 modemStatusReceived = false; 4389 addModemStatusListener(resetStatusListener); 4390 synchronized (resetLock) { 4391 try { 4392 resetLock.wait(TIMEOUT_RESET); 4393 } catch (InterruptedException e) { } 4394 } 4395 removeModemStatusListener(resetStatusListener); 4396 return modemStatusReceived; 4397 } 4398 4399 /** 4400 * Custom listener for modem reset packets. 4401 * 4402 * <p>When a Modem Status packet is received with status 4403 * {@code ModemStatusEvent.STATUS_HARDWARE_RESET} or 4404 * {@code ModemStatusEvent.STATUS_WATCHDOG_TIMER_RESET}, it 4405 * notifies the object that was waiting for the reception.</p> 4406 * 4407 * @see com.digi.xbee.api.listeners.IModemStatusReceiveListener 4408 * @see com.digi.xbee.api.models.ModemStatusEvent#STATUS_HARDWARE_RESET 4409 * @see com.digi.xbee.api.models.ModemStatusEvent#STATUS_WATCHDOG_TIMER_RESET 4410 */ 4411 private IModemStatusReceiveListener resetStatusListener = new IModemStatusReceiveListener() { 4412 4413 /* 4414 * (non-Javadoc) 4415 * @see com.digi.xbee.api.listeners.IModemStatusReceiveListener#modemStatusEventReceived(com.digi.xbee.api.models.ModemStatusEvent) 4416 */ 4417 @Override 4418 public void modemStatusEventReceived(ModemStatusEvent modemStatusEvent) { 4419 if (modemStatusEvent == ModemStatusEvent.STATUS_HARDWARE_RESET 4420 || modemStatusEvent == ModemStatusEvent.STATUS_WATCHDOG_TIMER_RESET){ 4421 modemStatusReceived = true; 4422 // Continue execution by notifying the lock object. 4423 synchronized (resetLock) { 4424 resetLock.notify(); 4425 } 4426 } 4427 } 4428 }; 4429 4430 /** 4431 * Performs a software reset on this XBee device and blocks until the 4432 * process is completed. 4433 * 4434 * @throws TimeoutException if the configured time expires while waiting 4435 * for the command reply. 4436 * @throws XBeeException if there is any other XBee related exception. 4437 */ 4438 protected void softwareReset() throws TimeoutException, XBeeException { 4439 // Check connection. 4440 if (!connectionInterface.isOpen()) 4441 throw new InterfaceNotOpenException(); 4442 4443 logger.info(toString() + "Resetting the local module..."); 4444 4445 ATCommandResponse response = null; 4446 try { 4447 response = sendATCommand(new ATCommand("FR")); 4448 } catch (IOException e) { 4449 throw new XBeeException("Error writing in the communication interface.", e); 4450 } 4451 4452 // Check if AT Command response is valid. 4453 checkATCommandResponseIsValid(response); 4454 4455 // Wait for a Modem Status packet. 4456 if (!waitForModemResetStatusPacket()) 4457 throw new TimeoutException("Timeout waiting for the Modem Status packet."); 4458 4459 logger.info(toString() + "Module reset successfully."); 4460 } 4461 4462 /** 4463 * Reads new packet received by this XBee device during the configured 4464 * receive timeout. 4465 * 4466 * <p>This method blocks until new packet is received or the configured 4467 * receive timeout expires.</p> 4468 * 4469 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 4470 * method and can be consulted with {@code getReceiveTimeout} method.</p> 4471 * 4472 * <p>For non-blocking operations, register a {@code IPacketReceiveListener} 4473 * using the method {@link #addPacketListener(IPacketReceiveListener)}.</p> 4474 * 4475 * @return The received XBee packet, or {@code null} if none was received 4476 * during the configured timeout. 4477 * 4478 * @throws InterfaceNotOpenException if this device connection is not open. 4479 * 4480 * @see #getReceiveTimeout() 4481 * @see #setReceiveTimeout(int) 4482 * @see #readPacket(int) 4483 * @see #readPacketFrom(RemoteXBeeDevice) 4484 * @see #readPacketFrom(RemoteXBeeDevice, int) 4485 * @see XBeePacket 4486 */ 4487 protected XBeePacket readPacket() { 4488 return readPacket(null, TIMEOUT_READ_PACKET); 4489 } 4490 4491 /** 4492 * Reads new packet received by this XBee device during the provided 4493 * timeout. 4494 * 4495 * <p>This method blocks until new packet is received or the provided 4496 * timeout expires.</p> 4497 * 4498 * <p>For non-blocking operations, register a {@code IPacketReceiveListener} 4499 * using the method {@link #addPacketListener(IPacketReceiveListener)}.</p> 4500 * 4501 * @param timeout The time to wait for new packet in milliseconds. 4502 * 4503 * @return The received XBee packet, or {@code null} if none was received 4504 * during the provided timeout. 4505 * 4506 * @throws IllegalArgumentException if {@code timeout < 0}. 4507 * @throws InterfaceNotOpenException if this device connection is not open. 4508 * 4509 * @see #readPacket() 4510 * @see #readPacketFrom(RemoteXBeeDevice) 4511 * @see #readPacketFrom(RemoteXBeeDevice, int) 4512 * @see XBeePacket 4513 */ 4514 protected XBeePacket readPacket(int timeout) { 4515 if (timeout < 0) 4516 throw new IllegalArgumentException("Read timeout must be 0 or greater."); 4517 4518 return readPacket(null, timeout); 4519 } 4520 4521 /** 4522 * Reads new packet received from the given remote XBee device during the 4523 * configured receive timeout. 4524 * 4525 * <p>This method blocks until new packet from the provided remote XBee 4526 * device is received or the configured receive timeout expires.</p> 4527 * 4528 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 4529 * method and can be consulted with {@code getReceiveTimeout} method.</p> 4530 * 4531 * <p>For non-blocking operations, register a {@code IPacketReceiveListener} 4532 * using the method {@link #addPacketListener(IPacketReceiveListener)}.</p> 4533 * 4534 * @param remoteXBeeDevice The remote device to read packet from. 4535 * 4536 * @return The received XBee packet, or {@code null} if none was received 4537 * from the given remote device during the configured timeout. 4538 * 4539 * @throws InterfaceNotOpenException if this device connection is not open. 4540 * @throws NullPointerException if {@code remoteXBeeDevice == null}. 4541 * 4542 * @see #getReceiveTimeout() 4543 * @see #setReceiveTimeout(int) 4544 * @see #readPacket() 4545 * @see #readPacket(int) 4546 * @see #readPacketFrom(RemoteXBeeDevice, int) 4547 * @see XBeePacket 4548 */ 4549 protected XBeePacket readPacketFrom(RemoteXBeeDevice remoteXBeeDevice) { 4550 if (remoteXBeeDevice == null) 4551 throw new NullPointerException("Remote XBee device cannot be null."); 4552 4553 return readPacketFrom(remoteXBeeDevice, TIMEOUT_READ_PACKET); 4554 } 4555 4556 /** 4557 * Reads new packet received from the given remote XBee device during the 4558 * provided timeout. 4559 * 4560 * <p>This method blocks until new packet from the provided remote XBee 4561 * device is received or the given timeout expires.</p> 4562 * 4563 * <p>For non-blocking operations, register a {@code IPacketReceiveListener} 4564 * using the method {@link #addPacketListener(IPacketReceiveListener)}.</p> 4565 * 4566 * @param remoteXBeeDevice The remote device to read packet from. 4567 * @param timeout The time to wait for new packet in milliseconds. 4568 * 4569 * @return The received XBee packet, or {@code null} if none was received 4570 * from the given remote device during the provided timeout. 4571 * 4572 * @throws IllegalArgumentException if {@code timeout < 0}. 4573 * @throws InterfaceNotOpenException if this device connection is not open. 4574 * @throws NullPointerException if {@code remoteXBeeDevice == null}. 4575 * 4576 * @see #readPacket() 4577 * @see #readPacket(int) 4578 * @see #readPacketFrom(RemoteXBeeDevice) 4579 * @see XBeePacket 4580 */ 4581 protected XBeePacket readPacketFrom(RemoteXBeeDevice remoteXBeeDevice, int timeout) { 4582 if (remoteXBeeDevice == null) 4583 throw new NullPointerException("Remote XBee device cannot be null."); 4584 if (timeout < 0) 4585 throw new IllegalArgumentException("Read timeout must be 0 or greater."); 4586 4587 return readPacket(remoteXBeeDevice, timeout); 4588 } 4589 4590 /** 4591 * Reads a new packet received by this XBee device during the provided 4592 * timeout. 4593 * 4594 * <p>This method blocks until new packet is received or the given timeout 4595 * expires.</p> 4596 * 4597 * <p>If the provided remote XBee device is {@code null} the method returns 4598 * the first packet read from any remote device. 4599 * <br> 4600 * If the remote device is not {@code null} the method returns the first 4601 * packet read from the provided device.</p> 4602 * 4603 * @param remoteXBeeDevice The remote device to get a packet from. 4604 * {@code null} to read a packet sent by any 4605 * remote XBee device. 4606 * @param timeout The time to wait for a packet in milliseconds. 4607 * 4608 * @return The received XBee packet, or {@code null} if none was received 4609 * from the given remote device during the provided timeout. 4610 * 4611 * @throws InterfaceNotOpenException if this device connection is not open. 4612 * 4613 * @see RemoteXBeeDevice 4614 * @see XBeePacket 4615 */ 4616 private XBeePacket readPacket(RemoteXBeeDevice remoteXBeeDevice, int timeout) { 4617 // Check connection. 4618 if (!connectionInterface.isOpen()) 4619 throw new InterfaceNotOpenException(); 4620 4621 XBeePacketsQueue xbeePacketsQueue = dataReader.getXBeePacketsQueue(); 4622 4623 if (remoteXBeeDevice != null) 4624 return xbeePacketsQueue.getFirstPacketFrom(remoteXBeeDevice, timeout); 4625 else 4626 return xbeePacketsQueue.getFirstPacket(timeout); 4627 } 4628 4629 /** 4630 * Reads new data received by this XBee device during the configured 4631 * receive timeout. 4632 * 4633 * <p>This method blocks until new data is received or the configured 4634 * receive timeout expires.</p> 4635 * 4636 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 4637 * method and can be consulted with {@code getReceiveTimeout} method.</p> 4638 * 4639 * <p>For non-blocking operations, register a {@code IDataReceiveListener} 4640 * using the method {@link #addDataListener(IDataReceiveListener)}.</p> 4641 * 4642 * @return An {@code XBeeMessage} object containing the data and the source 4643 * address of the remote node that sent the data. {@code null} if 4644 * this did not receive new data during the configured receive 4645 * timeout. 4646 * 4647 * @throws InterfaceNotOpenException if this device connection is not open. 4648 * 4649 * @see #readData(int) 4650 * @see #getReceiveTimeout() 4651 * @see #setReceiveTimeout(int) 4652 * @see #readDataFrom(RemoteXBeeDevice) 4653 * @see #readDataFrom(RemoteXBeeDevice, int) 4654 * @see com.digi.xbee.api.models.XBeeMessage 4655 */ 4656 protected XBeeMessage readData() { 4657 return readDataPacket(null, TIMEOUT_READ_PACKET); 4658 } 4659 4660 /** 4661 * Reads new data received by this XBee device during the provided timeout. 4662 * 4663 * <p>This method blocks until new data is received or the provided timeout 4664 * expires.</p> 4665 * 4666 * <p>For non-blocking operations, register a {@code IDataReceiveListener} 4667 * using the method {@link #addDataListener(IDataReceiveListener)}.</p> 4668 * 4669 * @param timeout The time to wait for new data in milliseconds. 4670 * 4671 * @return An {@code XBeeMessage} object containing the data and the source 4672 * address of the remote node that sent the data. {@code null} if 4673 * this device did not receive new data during {@code timeout} 4674 * milliseconds. 4675 * 4676 * @throws IllegalArgumentException if {@code timeout < 0}. 4677 * @throws InterfaceNotOpenException if this device connection is not open. 4678 * 4679 * @see #readData() 4680 * @see #readDataFrom(RemoteXBeeDevice) 4681 * @see #readDataFrom(RemoteXBeeDevice, int) 4682 * @see com.digi.xbee.api.models.XBeeMessage 4683 */ 4684 protected XBeeMessage readData(int timeout) { 4685 if (timeout < 0) 4686 throw new IllegalArgumentException("Read timeout must be 0 or greater."); 4687 4688 return readDataPacket(null, timeout); 4689 } 4690 4691 /** 4692 * Reads new data received from the given remote XBee device during the 4693 * configured receive timeout. 4694 * 4695 * <p>This method blocks until new data from the provided remote XBee 4696 * device is received or the configured receive timeout expires.</p> 4697 * 4698 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 4699 * method and can be consulted with {@code getReceiveTimeout} method.</p> 4700 * 4701 * <p>For non-blocking operations, register a {@code IDataReceiveListener} 4702 * using the method {@link #addDataListener(IDataReceiveListener)}.</p> 4703 * 4704 * @param remoteXBeeDevice The remote device to read data from. 4705 * 4706 * @return An {@code XBeeMessage} object containing the data and the source 4707 * address of the remote node that sent the data. {@code null} if 4708 * this device did not receive new data from the provided remote 4709 * XBee device during the configured receive timeout. 4710 * 4711 * @throws InterfaceNotOpenException if this device connection is not open. 4712 * @throws NullPointerException if {@code remoteXBeeDevice == null}. 4713 * 4714 * @see #readDataFrom(RemoteXBeeDevice, int) 4715 * @see #getReceiveTimeout() 4716 * @see #setReceiveTimeout(int) 4717 * @see #readData() 4718 * @see #readData(int) 4719 * @see RemoteXBeeDevice 4720 * @see com.digi.xbee.api.models.XBeeMessage 4721 */ 4722 protected XBeeMessage readDataFrom(RemoteXBeeDevice remoteXBeeDevice) { 4723 if (remoteXBeeDevice == null) 4724 throw new NullPointerException("Remote XBee device cannot be null."); 4725 4726 return readDataPacket(remoteXBeeDevice, TIMEOUT_READ_PACKET); 4727 } 4728 4729 /** 4730 * Reads new data received from the given remote XBee device during the 4731 * provided timeout. 4732 * 4733 * <p>This method blocks until new data from the provided remote XBee 4734 * device is received or the given timeout expires.</p> 4735 * 4736 * <p>For non-blocking operations, register a {@code IDataReceiveListener} 4737 * using the method {@link #addDataListener(IDataReceiveListener)}.</p> 4738 * 4739 * @param remoteXBeeDevice The remote device to read data from. 4740 * @param timeout The time to wait for new data in milliseconds. 4741 * 4742 * @return An {@code XBeeMessage} object containing the data and the source 4743 * address of the remote node that sent the data. {@code null} if 4744 * this device did not receive new data from the provided remote 4745 * XBee device during {@code timeout} milliseconds. 4746 * 4747 * @throws IllegalArgumentException if {@code timeout < 0}. 4748 * @throws InterfaceNotOpenException if this device connection is not open. 4749 * @throws NullPointerException if {@code remoteXBeeDevice == null}. 4750 * 4751 * @see #readDataFrom(RemoteXBeeDevice) 4752 * @see #getReceiveTimeout() 4753 * @see #setReceiveTimeout(int) 4754 * @see #readData() 4755 * @see #readData(int) 4756 * @see RemoteXBeeDevice 4757 * @see com.digi.xbee.api.models.XBeeMessage 4758 */ 4759 protected XBeeMessage readDataFrom(RemoteXBeeDevice remoteXBeeDevice, int timeout) { 4760 if (remoteXBeeDevice == null) 4761 throw new NullPointerException("Remote XBee device cannot be null."); 4762 if (timeout < 0) 4763 throw new IllegalArgumentException("Read timeout must be 0 or greater."); 4764 4765 return readDataPacket(remoteXBeeDevice, timeout); 4766 } 4767 4768 /** 4769 * Reads a new data packet received by this XBee device during the provided 4770 * timeout. 4771 * 4772 * <p>This method blocks until new data is received or the given timeout 4773 * expires.</p> 4774 * 4775 * <p>If the provided remote XBee device is {@code null} the method returns 4776 * the first data packet read from any remote device. 4777 * <br> 4778 * If the remote device is not {@code null} the method returns the first 4779 * data package read from the provided device. 4780 * </p> 4781 * 4782 * @param remoteXBeeDevice The remote device to get a data packet from. 4783 * {@code null} to read a data packet sent by any 4784 * remote XBee device. 4785 * @param timeout The time to wait for a data packet in milliseconds. 4786 * 4787 * @return An {@code XBeeMessage} received by this device, containing the 4788 * data and the source address of the remote node that sent the 4789 * data. {@code null} if this device did not receive new data 4790 * during {@code timeout} milliseconds, or if any error occurs while 4791 * trying to get the source of the message. 4792 * 4793 * @throws InterfaceNotOpenException if this device connection is not open. 4794 * 4795 * @see RemoteXBeeDevice 4796 * @see com.digi.xbee.api.models.XBeeMessage 4797 */ 4798 private XBeeMessage readDataPacket(RemoteXBeeDevice remoteXBeeDevice, int timeout) { 4799 // Check connection. 4800 if (!connectionInterface.isOpen()) 4801 throw new InterfaceNotOpenException(); 4802 4803 XBeePacketsQueue xbeePacketsQueue = dataReader.getXBeePacketsQueue(); 4804 XBeePacket xbeePacket = null; 4805 4806 if (remoteXBeeDevice != null) 4807 xbeePacket = xbeePacketsQueue.getFirstDataPacketFrom(remoteXBeeDevice, timeout); 4808 else 4809 xbeePacket = xbeePacketsQueue.getFirstDataPacket(timeout); 4810 4811 if (xbeePacket == null) 4812 return null; 4813 4814 // Obtain the remote device from the packet. 4815 RemoteXBeeDevice remoteDevice = null; 4816 try { 4817 remoteDevice = dataReader.getRemoteXBeeDeviceFromPacket((XBeeAPIPacket)xbeePacket); 4818 // If the provided device is not null, add it to the network, so the 4819 // device provided is the one that will remain in the network. 4820 if (remoteXBeeDevice != null) 4821 remoteDevice = getNetwork().addRemoteDevice(remoteXBeeDevice); 4822 4823 // The packet always contains information of the source so the 4824 // remote device should never be null. 4825 if (remoteDevice == null) 4826 return null; 4827 4828 } catch (XBeeException e) { 4829 logger.error(e.getMessage(), e); 4830 return null; 4831 } 4832 4833 // Obtain the data from the packet. 4834 byte[] data = null; 4835 4836 switch (((XBeeAPIPacket)xbeePacket).getFrameType()) { 4837 case RECEIVE_PACKET: 4838 ReceivePacket receivePacket = (ReceivePacket)xbeePacket; 4839 data = receivePacket.getRFData(); 4840 break; 4841 case RX_16: 4842 RX16Packet rx16Packet = (RX16Packet)xbeePacket; 4843 data = rx16Packet.getRFData(); 4844 break; 4845 case RX_64: 4846 RX64Packet rx64Packet = (RX64Packet)xbeePacket; 4847 data = rx64Packet.getRFData(); 4848 break; 4849 default: 4850 return null; 4851 } 4852 4853 // Create and return the XBee message. 4854 return new XBeeMessage(remoteDevice, data, ((XBeeAPIPacket)xbeePacket).isBroadcast()); 4855 } 4856 4857 /** 4858 * Reads new explicit data received by this XBee device during the 4859 * configured receive timeout. 4860 * 4861 * <p>This method blocks until new explicit data is received or the 4862 * configured receive timeout expires.</p> 4863 * 4864 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 4865 * method and can be consulted with {@code getReceiveTimeout} method.</p> 4866 * 4867 * <p>For non-blocking operations, register a 4868 * {@code IExplicitDataReceiveListener} using the method 4869 * {@link #addExplicitDataListener(IExplicitDataReceiveListener)}.</p> 4870 * 4871 * @return An {@code ExplicitXBeeMessage} object containing the explicit 4872 * data, the source address of the remote node that sent the data 4873 * and other values related to the transmission. {@code null} if 4874 * this did not receive new explicit data during the configured 4875 * receive timeout. 4876 * 4877 * @throws InterfaceNotOpenException if this device connection is not open. 4878 * 4879 * @see #getReceiveTimeout() 4880 * @see #readExplicitData(int) 4881 * @see #readExplicitDataFrom(RemoteXBeeDevice) 4882 * @see #readExplicitDataFrom(RemoteXBeeDevice, int) 4883 * @see #setReceiveTimeout(int) 4884 * @see com.digi.xbee.api.models.ExplicitXBeeMessage 4885 */ 4886 protected ExplicitXBeeMessage readExplicitData() { 4887 return readExplicitDataPacket(null, TIMEOUT_READ_PACKET); 4888 } 4889 4890 /** 4891 * Reads new explicit data received by this XBee device during the provided 4892 * timeout. 4893 * 4894 * <p>This method blocks until new explicit data is received or the 4895 * provided timeout expires.</p> 4896 * 4897 * <p>For non-blocking operations, register a 4898 * {@code IExplicitDataReceiveListener} using the method 4899 * {@link #addExplicitDataListener(IExplicitDataReceiveListener)}.</p> 4900 * 4901 * @param timeout The time to wait for new explicit data in milliseconds. 4902 * 4903 * @return An {@code ExplicitXBeeMessage} object containing the explicit 4904 * data, the source address of the remote node that sent the data 4905 * and other values related to the transmission. {@code null} if 4906 * this device did not receive new explicit data during 4907 * {@code timeout} milliseconds. 4908 * 4909 * @throws IllegalArgumentException if {@code timeout < 0}. 4910 * @throws InterfaceNotOpenException if this device connection is not open. 4911 * 4912 * @see #readExplicitData() 4913 * @see #readExplicitDataFrom(RemoteXBeeDevice) 4914 * @see #readExplicitDataFrom(RemoteXBeeDevice, int) 4915 * @see com.digi.xbee.api.models.ExplicitXBeeMessage 4916 */ 4917 protected ExplicitXBeeMessage readExplicitData(int timeout) { 4918 if (timeout < 0) 4919 throw new IllegalArgumentException("Read timeout must be 0 or greater."); 4920 4921 return readExplicitDataPacket(null, timeout); 4922 } 4923 4924 /** 4925 * Reads new explicit data received from the given remote XBee device 4926 * during the configured receive timeout. 4927 * 4928 * <p>This method blocks until new explicit data from the provided remote 4929 * XBee device is received or the configured receive timeout expires.</p> 4930 * 4931 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 4932 * method and can be consulted with {@code getReceiveTimeout} method.</p> 4933 * 4934 * <p>For non-blocking operations, register a 4935 * {@code IExplicitDataReceiveListener} using the method 4936 * {@link #addExplicitDataListener(IExplicitDataReceiveListener)}.</p> 4937 * 4938 * @param remoteXBeeDevice The remote device to read explicit data from. 4939 * 4940 * @return An {@code ExplicitXBeeMessage} object containing the explicit 4941 * data, the source address of the remote node that sent the data 4942 * and other values related to the transmission. {@code null} if 4943 * this device did not receive new explicit data from the provided 4944 * remote XBee device during the configured receive timeout. 4945 * 4946 * @throws InterfaceNotOpenException if this device connection is not open. 4947 * @throws NullPointerException if {@code remoteXBeeDevice == null}. 4948 * 4949 * @see #getReceiveTimeout() 4950 * @see #readExplicitData() 4951 * @see #readExplicitData(int) 4952 * @see #readExplicitDataFrom(RemoteXBeeDevice, int) 4953 * @see #setReceiveTimeout(int) 4954 * @see RemoteXBeeDevice 4955 * @see com.digi.xbee.api.models.ExplicitXBeeMessage 4956 */ 4957 protected ExplicitXBeeMessage readExplicitDataFrom(RemoteXBeeDevice remoteXBeeDevice) { 4958 if (remoteXBeeDevice == null) 4959 throw new NullPointerException("Remote XBee device cannot be null."); 4960 4961 return readExplicitDataPacket(remoteXBeeDevice, TIMEOUT_READ_PACKET); 4962 } 4963 4964 /** 4965 * Reads new explicit data received from the given remote XBee device 4966 * during the provided timeout. 4967 * 4968 * <p>This method blocks until new explicit data from the provided remote 4969 * XBee device is received or the given timeout expires.</p> 4970 * 4971 * <p>For non-blocking operations, register a 4972 * {@code IExplicitDataReceiveListener} using the method 4973 * {@link #addExplicitDataListener(IExplicitDataReceiveListener)}.</p> 4974 * 4975 * @param remoteXBeeDevice The remote device to read explicit data from. 4976 * @param timeout The time to wait for new explicit data in milliseconds. 4977 * 4978 * @return An {@code ExplicitXBeeMessage} object containing the explicit 4979 * data, the source address of the remote node that sent the data 4980 * and other values related to the transmission. {@code null} if 4981 * this device did not receive new data from the provided remote 4982 * XBee device during {@code timeout} milliseconds. 4983 * 4984 * @throws IllegalArgumentException if {@code timeout < 0}. 4985 * @throws InterfaceNotOpenException if this device connection is not open. 4986 * @throws NullPointerException if {@code remoteXBeeDevice == null}. 4987 * 4988 * @see #getReceiveTimeout() 4989 * @see #readExplicitData() 4990 * @see #readExplicitData(int) 4991 * @see #readExplicitDataFrom(RemoteXBeeDevice) 4992 * @see #setReceiveTimeout(int) 4993 * @see RemoteXBeeDevice 4994 * @see com.digi.xbee.api.models.ExplicitXBeeMessage 4995 */ 4996 protected ExplicitXBeeMessage readExplicitDataFrom(RemoteXBeeDevice remoteXBeeDevice, int timeout) { 4997 if (remoteXBeeDevice == null) 4998 throw new NullPointerException("Remote XBee device cannot be null."); 4999 if (timeout < 0) 5000 throw new IllegalArgumentException("Read timeout must be 0 or greater."); 5001 5002 return readExplicitDataPacket(remoteXBeeDevice, timeout); 5003 } 5004 5005 /** 5006 * Reads a new explicit data packet received by this XBee device during 5007 * the provided timeout. 5008 * 5009 * <p>This method blocks until new explicit data is received or the given 5010 * timeout expires.</p> 5011 * 5012 * <p>If the provided remote XBee device is {@code null} the method returns 5013 * the first explicit data packet read from any remote device. 5014 * <br> 5015 * If the remote device is not {@code null} the method returns the first 5016 * explicit data package read from the provided device. 5017 * </p> 5018 * 5019 * @param remoteXBeeDevice The remote device to get an explicit data 5020 * packet from. {@code null} to read an explicit 5021 * data packet sent by any remote XBee device. 5022 * @param timeout The time to wait for an explicit data packet in 5023 * milliseconds. 5024 * 5025 * @return An {@code XBeeMessage} received by this device, containing the 5026 * explicit data and the source address of the remote node that 5027 * sent the data. {@code null} if this device did not receive new 5028 * explicit data during {@code timeout} milliseconds. 5029 * 5030 * @throws InterfaceNotOpenException if this device connection is not open. 5031 * 5032 * @see RemoteXBeeDevice 5033 * @see com.digi.xbee.api.models.ExplicitXBeeMessage 5034 */ 5035 private ExplicitXBeeMessage readExplicitDataPacket(RemoteXBeeDevice remoteXBeeDevice, int timeout) { 5036 // Check connection. 5037 if (!connectionInterface.isOpen()) 5038 throw new InterfaceNotOpenException(); 5039 5040 if (isRemote()) 5041 throw new RuntimeException("Remote devices cannot read explicit data."); 5042 5043 XBeePacketsQueue xbeePacketsQueue = dataReader.getXBeePacketsQueue(); 5044 XBeePacket xbeePacket = null; 5045 5046 if (remoteXBeeDevice != null) 5047 xbeePacket = xbeePacketsQueue.getFirstExplicitDataPacketFrom(remoteXBeeDevice, timeout); 5048 else 5049 xbeePacket = xbeePacketsQueue.getFirstExplicitDataPacket(timeout); 5050 5051 if (xbeePacket == null) 5052 return null; 5053 5054 // Verify the packet is an explicit data packet. 5055 APIFrameType packetType = ((XBeeAPIPacket)xbeePacket).getFrameType(); 5056 if (packetType != APIFrameType.EXPLICIT_RX_INDICATOR) 5057 return null; 5058 5059 // Obtain the necessary data from the packet. 5060 ExplicitRxIndicatorPacket explicitDataPacket = (ExplicitRxIndicatorPacket)xbeePacket; 5061 RemoteXBeeDevice remoteDevice = getNetwork().getDevice(explicitDataPacket.get64BitSourceAddress()); 5062 if (remoteDevice == null) { 5063 if (remoteXBeeDevice != null) 5064 remoteDevice = remoteXBeeDevice; 5065 else 5066 remoteDevice = new RemoteXBeeDevice(this, explicitDataPacket.get64BitSourceAddress()); 5067 getNetwork().addRemoteDevice(remoteDevice); 5068 } 5069 int sourceEndpoint = explicitDataPacket.getSourceEndpoint(); 5070 int destEndpoint = explicitDataPacket.getDestinationEndpoint(); 5071 int clusterID = explicitDataPacket.getClusterID(); 5072 int profileID = explicitDataPacket.getProfileID(); 5073 byte[] data = explicitDataPacket.getRFData(); 5074 5075 // Create and return the XBee message. 5076 return new ExplicitXBeeMessage(remoteDevice, sourceEndpoint, destEndpoint, clusterID, profileID, data, ((XBeeAPIPacket)xbeePacket).isBroadcast()); 5077 } 5078 5079 /** 5080 * Configures the API output mode of the XBee device. 5081 * 5082 * <p>The API output mode determines the format that the received data is 5083 * output through the serial interface of the XBee device.</p> 5084 * 5085 * @param apiOutputMode The API output mode to be set to the XBee device. 5086 * 5087 * @throws InterfaceNotOpenException if this device connection is not open. 5088 * @throws NullPointerException if {@code apiOutputMode == null}. 5089 * @throws TimeoutException if there is a timeout configuring the API 5090 * output mode. 5091 * @throws XBeeException if there is any other XBee related exception. 5092 * 5093 * @see #getAPIOutputMode() 5094 * @see APIOutputMode 5095 */ 5096 protected void setAPIOutputMode(APIOutputMode apiOutputMode) throws TimeoutException, XBeeException { 5097 if (apiOutputMode == null) 5098 throw new NullPointerException("API output mode cannot be null."); 5099 5100 setParameter("AO", new byte[]{(byte)apiOutputMode.getValue()}); 5101 } 5102 5103 /** 5104 * Returns the API output mode of the XBee device. 5105 * 5106 * <p>The API output mode determines the format that the received data is 5107 * output through the serial interface of the XBee device.</p> 5108 * 5109 * @return The API output mode that the XBee device is configured with. 5110 * 5111 * @throws InterfaceNotOpenException if this device connection is not open. 5112 * @throws TimeoutException if there is a timeout getting the API output 5113 * mode from the device. 5114 * @throws XBeeException if there is any other XBee related exception. 5115 * 5116 * @see #setAPIOutputMode(APIOutputMode) 5117 * @see APIOutputMode 5118 */ 5119 protected APIOutputMode getAPIOutputMode() throws TimeoutException, XBeeException { 5120 byte[] apiOutputModeValue = getParameter("AO"); 5121 5122 return APIOutputMode.get(apiOutputModeValue[0]); 5123 } 5124 5125 /** 5126 * Sets the password of this Bluetooth device in order to connect to it. 5127 * 5128 * <p>The Bluetooth password must be provided before calling the 5129 * {@link #open()} method.</p> 5130 * 5131 * @param password The password of this Bluetooth device. 5132 * 5133 * @since 1.3.0 5134 */ 5135 protected void setBluetoothPassword(String password) { 5136 this.bluetoothPassword = password; 5137 } 5138}