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