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.net.Inet6Address; 019import java.net.UnknownHostException; 020 021import com.digi.xbee.api.connection.IConnectionInterface; 022import com.digi.xbee.api.connection.serial.SerialPortParameters; 023import com.digi.xbee.api.exceptions.InterfaceNotOpenException; 024import com.digi.xbee.api.exceptions.OperationNotSupportedException; 025import com.digi.xbee.api.exceptions.TimeoutException; 026import com.digi.xbee.api.exceptions.XBeeException; 027import com.digi.xbee.api.listeners.IDataReceiveListener; 028import com.digi.xbee.api.listeners.IIPDataReceiveListener; 029import com.digi.xbee.api.models.IPMessage; 030import com.digi.xbee.api.models.IPProtocol; 031import com.digi.xbee.api.models.XBee16BitAddress; 032import com.digi.xbee.api.models.XBee64BitAddress; 033import com.digi.xbee.api.models.XBeeMessage; 034import com.digi.xbee.api.models.XBeePacketsQueue; 035import com.digi.xbee.api.packet.XBeeAPIPacket; 036import com.digi.xbee.api.packet.XBeePacket; 037import com.digi.xbee.api.packet.thread.RXIPv6Packet; 038import com.digi.xbee.api.packet.thread.TXIPv6Packet; 039import com.digi.xbee.api.utils.ByteUtils; 040import com.digi.xbee.api.utils.HexUtils; 041 042/** 043 * This class provides common functionality for XBee IPv6 devices. 044 * 045 * @see ThreadDevice 046 * 047 * @since 1.2.1 048 */ 049public class IPv6Device extends XBeeDevice { 050 051 // Constants 052 private static final String OPERATION_EXCEPTION = "Operation not supported in this module."; 053 054 protected static final short DEFAULT_SOURCE_PORT = 9750; 055 056 protected static final IPProtocol DEFAULT_PROTOCOL = IPProtocol.TCP; 057 058 // Variables 059 protected int sourcePort = DEFAULT_SOURCE_PORT; 060 061 /** 062 * Class constructor. Instantiates a new {@code IPv6Device} object in 063 * the given port name and baud rate. 064 * 065 * @param port Serial port name where IPv6 device is attached to. 066 * @param baudRate Serial port baud rate to communicate with the device. 067 * Other connection parameters will be set as default (8 068 * data bits, 1 stop bit, no parity, no flow control). 069 * 070 * @throws IllegalArgumentException if {@code baudRate < 0}. 071 * @throws NullPointerException if {@code port == null}. 072 * 073 * @see #IPv6Device(IConnectionInterface) 074 * @see #IPv6Device(String, SerialPortParameters) 075 * @see #IPv6Device(String, int, int, int, int, int) 076 */ 077 protected IPv6Device(String port, int baudRate) { 078 this(XBee.createConnectiontionInterface(port, baudRate)); 079 } 080 081 /** 082 * Class constructor. Instantiates a new {@code IPv6Device} object in 083 * the given serial port name and settings. 084 * 085 * @param port Serial port name where IPv6 device is attached to. 086 * @param baudRate Serial port baud rate to communicate with the device. 087 * @param dataBits Serial port data bits. 088 * @param stopBits Serial port stop bits. 089 * @param parity Serial port parity. 090 * @param flowControl Serial port flow control. 091 * 092 * @throws IllegalArgumentException if {@code baudRate < 0} or 093 * if {@code dataBits < 0} or 094 * if {@code stopBits < 0} or 095 * if {@code parity < 0} or 096 * if {@code flowControl < 0}. 097 * @throws NullPointerException if {@code port == null}. 098 * 099 * @see #IPv6Device(IConnectionInterface) 100 * @see #IPv6Device(String, int) 101 * @see #IPv6Device(String, SerialPortParameters) 102 */ 103 protected IPv6Device(String port, int baudRate, int dataBits, int stopBits, 104 int parity, int flowControl) { 105 this(port, new SerialPortParameters(baudRate, dataBits, stopBits, parity, flowControl)); 106 } 107 108 /** 109 * Class constructor. Instantiates a new {@code IPv6Device} object in 110 * the given serial port name and parameters. 111 * 112 * @param port Serial port name where IPv6 device is attached to. 113 * @param serialPortParameters Object containing the serial port parameters. 114 * 115 * @throws NullPointerException if {@code port == null} or 116 * if {@code serialPortParameters == null}. 117 * 118 * @see #IPv6Device(IConnectionInterface) 119 * @see #IPv6Device(String, int) 120 * @see #IPv6Device(String, int, int, int, int, int) 121 * @see com.digi.xbee.api.connection.serial.SerialPortParameters 122 */ 123 protected IPv6Device(String port, SerialPortParameters serialPortParameters) { 124 this(XBee.createConnectiontionInterface(port, serialPortParameters)); 125 } 126 127 /** 128 * Class constructor. Instantiates a new {@code IPv6Device} object with 129 * the given connection interface. 130 * 131 * @param connectionInterface The connection interface with the physical 132 * IPv6 device. 133 * 134 * @throws NullPointerException if {@code connectionInterface == null} 135 * 136 * @see #IPv6Device(String, int) 137 * @see #IPv6Device(String, SerialPortParameters) 138 * @see #IPv6Device(String, int, int, int, int, int) 139 * @see com.digi.xbee.api.connection.IConnectionInterface 140 */ 141 protected IPv6Device(IConnectionInterface connectionInterface) { 142 super(connectionInterface); 143 } 144 145 /** 146 * @deprecated This protocol does not support the network functionality. 147 */ 148 @Override 149 public XBeeNetwork getNetwork() { 150 // IPv6 modules do not have a network of devices. 151 return null; 152 } 153 154 /* 155 * (non-Javadoc) 156 * @see com.digi.xbee.api.AbstractXBeeDevice#readDeviceInfo() 157 */ 158 @Override 159 public void readDeviceInfo() throws TimeoutException, XBeeException { 160 super.readDeviceInfo(); 161 // Generate the Mesh-Local IPv6 address. 162 byte[] response = getParameter("MY"); 163 try { 164 ipv6Address = (Inet6Address) Inet6Address.getByAddress(response); 165 } catch (UnknownHostException e) { 166 throw new XBeeException(e); 167 } 168 169 // Read the source port. 170 try { 171 response = getParameter("C0"); 172 sourcePort = ByteUtils.byteArrayToInt(response); 173 } catch (TimeoutException e) { 174 // Do not refresh the source port value if there is an error reading 175 // it from the module. 176 } catch (XBeeException e) { 177 // Do not refresh the source port value if there is an error reading 178 // it from the module. 179 } 180 } 181 182 /** 183 * @deprecated This protocol does not have an associated 16-bit address. 184 */ 185 @Override 186 public XBee16BitAddress get16BitAddress() { 187 // IPv6 modules do not have 16-bit address. 188 return null; 189 } 190 191 /** 192 * @deprecated Operation not supported in this protocol. Use 193 * {@link #getIPv6DestinationAddress()} instead. 194 * This method will raise an 195 * {@link UnsupportedOperationException}. 196 */ 197 @Override 198 public XBee64BitAddress getDestinationAddress() throws TimeoutException, 199 XBeeException { 200 // Not supported in IPv6 modules. 201 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 202 } 203 204 /** 205 * @deprecated Operation not supported in this protocol. Use 206 * {@link #setIPv6DestinationAddress(Inet6Address)} instead. 207 * This method will raise an 208 * {@link UnsupportedOperationException}. 209 */ 210 @Override 211 public void setDestinationAddress(XBee64BitAddress xbee64BitAddress) 212 throws TimeoutException, XBeeException { 213 // Not supported in IPv6 modules. 214 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 215 } 216 217 /** 218 * @deprecated Operation not supported in this protocol. This method will 219 * raise an {@link UnsupportedOperationException}. 220 */ 221 @Override 222 public void addDataListener(IDataReceiveListener listener) { 223 // Not supported in IPv6 modules. 224 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 225 } 226 227 /** 228 * @deprecated Operation not supported in this protocol. This method will 229 * raise an {@link UnsupportedOperationException}. 230 */ 231 @Override 232 public void removeDataListener(IDataReceiveListener listener) { 233 // Not supported in IPv6 modules. 234 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 235 } 236 237 /** 238 * @deprecated Operation not supported in this protocol. This method will 239 * raise an {@link UnsupportedOperationException}. 240 */ 241 @Override 242 public XBeeMessage readData() { 243 // Not supported in IPv6 modules. 244 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 245 } 246 247 /** 248 * @deprecated Operation not supported in this protocol. This method will 249 * raise an {@link UnsupportedOperationException}. 250 */ 251 @Override 252 public XBeeMessage readData(int timeout) { 253 // Not supported in IPv6 modules. 254 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 255 } 256 257 /** 258 * @deprecated Operation not supported in this protocol. This method will 259 * raise an {@link UnsupportedOperationException}. 260 */ 261 @Override 262 public XBeeMessage readDataFrom(RemoteXBeeDevice remoteXBeeDevice) { 263 // Not supported in IPv6 modules. 264 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 265 } 266 267 /** 268 * @deprecated Operation not supported in this protocol. This method will 269 * raise an {@link UnsupportedOperationException}. 270 */ 271 @Override 272 public XBeeMessage readDataFrom(RemoteXBeeDevice remoteXBeeDevice, 273 int timeout) { 274 // Not supported in IPv6 modules. 275 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 276 } 277 278 /** 279 * @deprecated Operation not supported in this protocol. This method will 280 * raise an {@link UnsupportedOperationException}. 281 */ 282 @Override 283 public void sendBroadcastData(byte[] data) throws TimeoutException, 284 XBeeException { 285 // Not supported in IPv6 modules. 286 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 287 } 288 289 /** 290 * @deprecated Operation not supported in this protocol. This method will 291 * raise an {@link UnsupportedOperationException}. 292 */ 293 @Override 294 public void sendData(RemoteXBeeDevice remoteXBeeDevice, byte[] data) 295 throws TimeoutException, XBeeException { 296 // Not supported in IPv6 modules. 297 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 298 } 299 300 /** 301 * @deprecated Operation not supported in this protocol. This method will 302 * raise an {@link UnsupportedOperationException}. 303 */ 304 @Override 305 public void sendDataAsync(RemoteXBeeDevice remoteXBeeDevice, byte[] data) 306 throws XBeeException { 307 // Not supported in IPv6 modules. 308 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 309 } 310 311 /* 312 * (non-Javadoc) 313 * @see com.digi.xbee.api.AbstractXBeeDevice#addIPDataListener(com.digi.xbee.api.listeners.IIPDataReceiveListener) 314 */ 315 @Override 316 public void addIPDataListener(IIPDataReceiveListener listener) { 317 super.addIPDataListener(listener); 318 } 319 320 /* 321 * (non-Javadoc) 322 * @see com.digi.xbee.api.AbstractXBeeDevice#removeIPDataListener(com.digi.xbee.api.listeners.IIPDataReceiveListener) 323 */ 324 @Override 325 public void removeIPDataListener(IIPDataReceiveListener listener) { 326 super.removeIPDataListener(listener); 327 } 328 329 /** 330 * Starts listening for incoming IPv6 transmissions in the provided port. 331 * 332 * @param sourcePort Port to listen for incoming transmissions. 333 * 334 * @throws IllegalArgumentException if {@code sourcePort < 0} or 335 * if {@code sourcePort > 65535}. 336 * @throws TimeoutException if there is a timeout setting the source port. 337 * @throws XBeeException if there is any error setting the source port. 338 * 339 * @see #stopListening() 340 */ 341 public void startListening(int sourcePort) throws TimeoutException, XBeeException { 342 if (sourcePort < 0 || sourcePort > 65535) 343 throw new IllegalArgumentException("Source port must be between 0 and 65535."); 344 345 setParameter("C0", ByteUtils.shortToByteArray((short)sourcePort)); 346 this.sourcePort = sourcePort; 347 } 348 349 /** 350 * Stops listening for incoming IPv6 transmissions. 351 * 352 * @throws TimeoutException if there is a timeout processing the operation. 353 * @throws XBeeException if there is any other XBee related exception. 354 * 355 * @see #startListening(int) 356 */ 357 public void stopListening() throws TimeoutException, XBeeException { 358 setParameter("C0", ByteUtils.shortToByteArray((short)0)); 359 sourcePort = 0; 360 } 361 362 /** 363 * Sends the provided IPv6 data to the given IPv6 address and port using 364 * the specified IPv6 protocol. 365 * 366 * <p>This method blocks till a success or error response arrives or the 367 * configured receive timeout expires.</p> 368 * 369 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 370 * method and can be consulted with {@code getReceiveTimeout} method.</p> 371 * 372 * <p>For non-blocking operations use the method 373 * {@link #sendIPDataAsync(Inet6Address, int, IPProtocol, byte[])}.</p> 374 * 375 * @param ipv6Address The IPv6 address to send IPv6 data to. 376 * @param destPort The destination port of the transmission. 377 * @param protocol The IPv6 protocol used for the transmission. 378 * @param data Byte array containing the IPv6 data to be sent. 379 * 380 * @throws IllegalArgumentException if {@code destPort < 0} or 381 * if {@code destPort > 65535} 382 * @throws InterfaceNotOpenException if this device connection is not open. 383 * @throws NullPointerException if {@code ipv6Address == null} or 384 * if {@code protocol == null} or 385 * if {@code data == null}. 386 * @throws TimeoutException if there is a timeout sending the data. 387 * @throws XBeeException if there is any other XBee related exception. 388 * 389 * @see #getReceiveTimeout() 390 * @see #sendIPDataAsync(Inet6Address, int, IPProtocol, byte[]) 391 * @see #setReceiveTimeout(int) 392 * @see com.digi.xbee.api.models.IPProtocol 393 * @see java.net.Inet6Address 394 */ 395 public void sendIPData(Inet6Address ipv6Address, int destPort, 396 IPProtocol protocol, byte[] data) throws TimeoutException, XBeeException { 397 sendIPData(ipv6Address, destPort, protocol, data, false); 398 } 399 400 /** 401 * Sends the provided IPv6 data to the given IPv6 address and port 402 * asynchronously using the specified IPv6 protocol. 403 * 404 * <p>Asynchronous transmissions do not wait for answer from the remote 405 * device or for transmit status packet.</p> 406 * 407 * @param ipv6Address The IPv6 address to send IPv6 data to. 408 * @param destPort The destination port of the transmission. 409 * @param protocol The IPv6 protocol used for the transmission. 410 * @param data Byte array containing the IPv6 data to be sent. 411 * 412 * @throws IllegalArgumentException if {@code destPort < 0} or 413 * if {@code destPort > 65535} 414 * @throws InterfaceNotOpenException if this device connection is not open. 415 * @throws NullPointerException if {@code ipv6Address == null} or 416 * if {@code protocol == null} or 417 * if {@code data == null}. 418 * @throws TimeoutException if there is a timeout sending the data. 419 * @throws XBeeException if there is any other XBee related exception. 420 * 421 * @see #sendIPData(Inet6Address, int, IPProtocol, byte[]) 422 * @see com.digi.xbee.api.models.IPProtocol 423 * @see java.net.Inet6Address 424 */ 425 public void sendIPDataAsync(Inet6Address ipv6Address, int destPort, 426 IPProtocol protocol, byte[] data) throws XBeeException { 427 sendIPData(ipv6Address, destPort, protocol, data, true); 428 } 429 430 /** 431 * Sends the provided IPv6 data to the given IPv6 address and port using 432 * the specified IPv6 protocol. 433 * 434 * <p>Transmissions can be performed synchronously or asynchronously. 435 * Synchronous operation blocks till a success or error response arrives 436 * or the configured receive timeout expires. Asynchronous transmissions 437 * do not wait for answer from the remote device or for transmit status 438 * packet.</p> 439 * 440 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 441 * method and can be consulted with {@code getReceiveTimeout} method.</p> 442 * 443 * <p>For synchronous operations use this method:</p> 444 * <ul> 445 * <li>{@link #sendIPData(Inet6Address, int, IPProtocol, byte[])}.</li> 446 * </ul> 447 * <p>For asynchronous operations use this one:</p> 448 * <ul> 449 * <li>{@link #sendIPDataAsync(Inet6Address, int, IPProtocol, byte[])}.</li> 450 * </ul> 451 * 452 * @param ipv6Address The IPv6 address to send IPv6 data to. 453 * @param destPort The destination port of the transmission. 454 * @param protocol The IPv6 protocol used for the transmission. 455 * @param data Byte array containing the IPv6 data to be sent. 456 * @param async Boolean that should be set to {@code true} if the 457 * transmission should be asynchronous, and {@code false} otherwise. 458 * 459 * @throws IllegalArgumentException if {@code destPort < 0} or 460 * if {@code destPort > 65535} 461 * @throws InterfaceNotOpenException if this device connection is not open. 462 * @throws NullPointerException if {@code ipv6Address == null} or 463 * if {@code protocol == null} or 464 * if {@code data == null}. 465 * @throws TimeoutException if there is a timeout sending the data. 466 * @throws XBeeException if there is any other XBee related exception. 467 * 468 * @see #getReceiveTimeout() 469 * @see #sendIPData(Inet6Address, int, IPProtocol, byte[]) 470 * @see #sendIPDataAsync(Inet6Address, int, IPProtocol, byte[]) 471 * @see #setReceiveTimeout(int) 472 * @see com.digi.xbee.api.models.IPProtocol 473 * @see java.net.Inet6Address 474 */ 475 private void sendIPData(Inet6Address ipv6Address, int destPort, 476 IPProtocol protocol, byte[] data, boolean async) throws XBeeException { 477 if (ipv6Address == null) 478 throw new NullPointerException("IPv6 address cannot be null"); 479 if (data == null) 480 throw new NullPointerException("Data cannot be null"); 481 if (destPort < 0 || destPort > 65535) 482 throw new IllegalArgumentException("Destination port must be between 0 and 65535."); 483 484 // Check if device is remote. 485 if (isRemote()) 486 throw new OperationNotSupportedException("Cannot send IPv6 data from a remote device."); 487 488 // The source port value depends on the protocol used in the transmission. For UDP, source port 489 // value must be the same as 'C0' one. For TCP it must be 0. 490 int sourcePort = this.sourcePort; 491 if (protocol != IPProtocol.UDP) 492 sourcePort = 0; 493 494 if (async) 495 logger.debug(toString() + "Sending IPv6 data asynchronously to {}:{} >> {}.", ipv6Address, 496 destPort, HexUtils.prettyHexString(data)); 497 else 498 logger.debug(toString() + "Sending IPv6 data to {}:{} >> {}.", ipv6Address, 499 destPort, HexUtils.prettyHexString(data)); 500 501 XBeePacket xbeePacket = new TXIPv6Packet(getNextFrameID(), ipv6Address, destPort, 502 sourcePort, protocol, data); 503 504 sendAndCheckXBeePacket(xbeePacket, async); 505 } 506 507 /** 508 * Reads new IPv6 data received by this XBee device during the 509 * configured receive timeout. 510 * 511 * <p>This method blocks until new IPv6 data is received or the 512 * configured receive timeout expires.</p> 513 * 514 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 515 * method and can be consulted with {@code getReceiveTimeout} method.</p> 516 * 517 * <p>For non-blocking operations, register a {@code IIPDataReceiveListener} 518 * using the method {@link #addIPDataListener(IIPDataReceiveListener)}.</p> 519 * 520 * <p>Before reading IPv6 data you need to start listening for incoming 521 * IPv6 data at a specific port. Use the {@code startListening} method 522 * for that purpose. When finished, you can use the {@code stopListening} 523 * method to stop listening for incoming IPv6 data.</p> 524 * 525 * @return A {@code IPMessage} object containing the IPv6 data and 526 * the IPv6 address that sent the data. {@code null} if this did not 527 * receive new IPv6 data during the configured receive timeout. 528 * 529 * @throws InterfaceNotOpenException if this device connection is not open. 530 * 531 * @see #getReceiveTimeout() 532 * @see #readIPData(int) 533 * @see #readIPDataFrom(Inet6Address) 534 * @see #readIPDataFrom(Inet6Address, int) 535 * @see #setReceiveTimeout(int) 536 * @see #startListening(int) 537 * @see #stopListening() 538 * @see com.digi.xbee.api.models.IPMessage 539 */ 540 public IPMessage readIPData() { 541 return readIPDataPacket(null, TIMEOUT_READ_PACKET); 542 } 543 544 /** 545 * Reads new IPv6 data received by this XBee device during the provided 546 * timeout. 547 * 548 * <p>This method blocks until new IPv6 data is received or the provided 549 * timeout expires.</p> 550 * 551 * <p>For non-blocking operations, register a {@code IIPDataReceiveListener} 552 * using the method {@link #addIPDataListener(IIPDataReceiveListener)}.</p> 553 * 554 * <p>Before reading IPv6 data you need to start listening for incoming 555 * IPv6 data at a specific port. Use the {@code startListening} method 556 * for that purpose. When finished, you can use the {@code stopListening} 557 * method to stop listening for incoming IPv6 data.</p> 558 * 559 * @param timeout The time to wait for new IPv6 data in milliseconds. 560 * 561 * @return A {@code IPMessage} object containing the data and the IPv6 562 * address that sent the data. {@code null} if this device did not 563 * receive new data during {@code timeout} milliseconds. 564 * 565 * @throws IllegalArgumentException if {@code timeout < 0}. 566 * @throws InterfaceNotOpenException if this device connection is not open. 567 * 568 * @see #readIPData() 569 * @see #readIPDataFrom(Inet6Address) 570 * @see #readIPDataFrom(Inet6Address, int) 571 * @see #startListening(int) 572 * @see #stopListening() 573 * @see com.digi.xbee.api.models.IPMessage 574 */ 575 public IPMessage readIPData(int timeout) { 576 if (timeout < 0) 577 throw new IllegalArgumentException("Read timeout must be 0 or greater."); 578 579 return readIPDataPacket(null, timeout); 580 } 581 582 /** 583 * Reads new IPv6 data received from the given IPv6 address during the 584 * configured receive timeout. 585 * 586 * <p>This method blocks until new data from the provided IPv6 address is 587 * received or the configured receive timeout expires.</p> 588 * 589 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 590 * method and can be consulted with {@code getReceiveTimeout} method.</p> 591 * 592 * <p>For non-blocking operations, register a {@code IIPDataReceiveListener} 593 * using the method {@link #addIPDataListener(IIPDataReceiveListener)}.</p> 594 * 595 * <p>Before reading IPv6 data you need to start listening for incoming 596 * IPv6 data at a specific port. Use the {@code startListening} method 597 * for that purpose. When finished, you can use the {@code stopListening} 598 * method to stop listening for incoming IPv6 data.</p> 599 * 600 * @param ipv6Address The IPv6 address to read data from. 601 * 602 * @return A {@code IPMessage} object containing the IPv6 data and 603 * the IPv6 address of the remote node that sent the data. 604 * {@code null} if this device did not receive new IPv6 data 605 * from the provided IPv6 address during the configured receive 606 * timeout. 607 * 608 * @throws InterfaceNotOpenException if this device connection is not open. 609 * @throws NullPointerException if {@code ipv6Address == null}. 610 * 611 * @see #getReceiveTimeout() 612 * @see #readIPData() 613 * @see #readIPData(int) 614 * @see #readIPDataFrom(Inet6Address, int) 615 * @see #setReceiveTimeout(int) 616 * @see #startListening(int) 617 * @see #stopListening() 618 * @see com.digi.xbee.api.models.IPMessage 619 * @see java.net.Inet6Address 620 */ 621 public IPMessage readIPDataFrom(Inet6Address ipv6Address) { 622 if (ipv6Address == null) 623 throw new NullPointerException("IPv6 address cannot be null."); 624 625 return readIPDataPacket(ipv6Address, TIMEOUT_READ_PACKET); 626 } 627 628 /** 629 * Reads new IPv6 data received from the given IPv6 address during the 630 * provided timeout. 631 * 632 * <p>This method blocks until new IPv6 data from the provided IPv6 633 * address is received or the given timeout expires.</p> 634 * 635 * <p>For non-blocking operations, register a {@code IIPDataReceiveListener} 636 * using the method {@link #addIPDataListener(IIPDataReceiveListener)}.</p> 637 * 638 * <p>Before reading IPv6 data you need to start listening for incoming 639 * IPv6 data at a specific port. Use the {@code startListening} method 640 * for that purpose. When finished, you can use the {@code stopListening} 641 * method to stop listening for incoming IPv6 data.</p> 642 * 643 * @param ipv6Address The IPv6 address to read data from. 644 * @param timeout The time to wait for new IPv6 data in milliseconds. 645 * 646 * @return An {@code IPMessage} object containing the IPv6 data and 647 * the IPv6 address that sent the data. {@code null} if this device 648 * did not receive new IPv6 data from the provided IPv6 address 649 * during {@code timeout} milliseconds. 650 * 651 * @throws IllegalArgumentException if {@code timeout < 0}. 652 * @throws InterfaceNotOpenException if this device connection is not open. 653 * @throws NullPointerException if {@code ipv6Address == null}. 654 * 655 * @see #readIPDataFrom(Inet6Address) 656 * @see #readIPData() 657 * @see #readIPData(int) 658 * @see #startListening(int) 659 * @see #stopListening() 660 * @see com.digi.xbee.api.models.IPMessage 661 * @see java.net.Inet6Address 662 */ 663 public IPMessage readIPDataFrom(Inet6Address ipv6Address, int timeout) { 664 if (ipv6Address == null) 665 throw new NullPointerException("IPv6 address cannot be null."); 666 if (timeout < 0) 667 throw new IllegalArgumentException("Read timeout must be 0 or greater."); 668 669 return readIPDataPacket(ipv6Address, timeout); 670 } 671 672 /** 673 * Reads a new IPv6 data packet received by this IPv6 XBee device during 674 * the provided timeout. 675 * 676 * <p>This method blocks until new IPv6 data is received or the given 677 * timeout expires.</p> 678 * 679 * <p>If the provided IPv6 address is {@code null} the method returns 680 * the first IPv6 data packet read from any IPv6 address. 681 * <br> 682 * If the IPv6 address is not {@code null} the method returns the first 683 * data package read from the provided IPv6 address. 684 * </p> 685 * 686 * @param remoteIPAddress The IPv6 address to get an IPv6 data packet from. 687 * {@code null} to read an IPv6 data packet from 688 * any IPv6 address. 689 * @param timeout The time to wait for a IPv6 data packet in milliseconds. 690 * 691 * @return A {@code IPMessage} received by this device, containing the 692 * data and the source IPv6 address that sent the IPv6 data. 693 * {@code null} if this device did not receive new IPv6 data 694 * during {@code timeout} milliseconds, or if any error occurs while 695 * trying to get the source of the message. 696 * 697 * @throws InterfaceNotOpenException if this device connection is not open. 698 * 699 * @see com.digi.xbee.api.models.IPMessage 700 * @see java.net.Inet6Address 701 */ 702 private IPMessage readIPDataPacket(Inet6Address remoteIPAddress, int timeout) { 703 // Check connection. 704 if (!connectionInterface.isOpen()) 705 throw new InterfaceNotOpenException(); 706 707 XBeePacketsQueue xbeePacketsQueue = dataReader.getXBeePacketsQueue(); 708 XBeePacket xbeePacket = null; 709 710 if (remoteIPAddress != null) 711 xbeePacket = xbeePacketsQueue.getFirstIPv6DataPacketFrom(remoteIPAddress, timeout); 712 else 713 xbeePacket = xbeePacketsQueue.getFirstIPv6DataPacket(timeout); 714 715 if (xbeePacket == null) 716 return null; 717 718 // Obtain the data and IPv6 address from the packet. 719 byte[] data = null; 720 Inet6Address ipv6Address = null; 721 int sourcePort; 722 int destPort; 723 IPProtocol protocol = IPProtocol.TCP; 724 725 switch (((XBeeAPIPacket)xbeePacket).getFrameType()) { 726 case RX_IPV6: 727 RXIPv6Packet receivePacket = (RXIPv6Packet)xbeePacket; 728 data = receivePacket.getData(); 729 ipv6Address = receivePacket.getSourceAddress(); 730 sourcePort = receivePacket.getSourcePort(); 731 destPort = receivePacket.getDestPort(); 732 break; 733 default: 734 return null; 735 } 736 737 // Create and return the IPv6 message. 738 return new IPMessage(ipv6Address, sourcePort, destPort, protocol, data); 739 } 740}