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.Inet4Address; 019import java.net.Inet6Address; 020import java.net.UnknownHostException; 021 022import com.digi.xbee.api.connection.IConnectionInterface; 023import com.digi.xbee.api.connection.serial.SerialPortParameters; 024import com.digi.xbee.api.exceptions.InterfaceNotOpenException; 025import com.digi.xbee.api.exceptions.OperationNotSupportedException; 026import com.digi.xbee.api.exceptions.TimeoutException; 027import com.digi.xbee.api.exceptions.XBeeException; 028import com.digi.xbee.api.listeners.IDataReceiveListener; 029import com.digi.xbee.api.listeners.IIPDataReceiveListener; 030import com.digi.xbee.api.models.IPMessage; 031import com.digi.xbee.api.models.IPProtocol; 032import com.digi.xbee.api.models.XBee16BitAddress; 033import com.digi.xbee.api.models.XBee64BitAddress; 034import com.digi.xbee.api.models.XBeeMessage; 035import com.digi.xbee.api.models.XBeePacketsQueue; 036import com.digi.xbee.api.packet.XBeeAPIPacket; 037import com.digi.xbee.api.packet.XBeePacket; 038import com.digi.xbee.api.packet.ip.RXIPv4Packet; 039import com.digi.xbee.api.packet.ip.TXIPv4Packet; 040import com.digi.xbee.api.utils.ByteUtils; 041import com.digi.xbee.api.utils.HexUtils; 042 043/** 044 * This class provides common functionality for XBee IP devices. 045 * 046 * @see CellularDevice 047 * @see WiFiDevice 048 * 049 * @since 1.2.0 050 */ 051public class IPDevice extends XBeeDevice { 052 053 // Constants 054 public static final String BROADCAST_IP = "255.255.255.255"; 055 056 private static final String OPERATION_EXCEPTION = "Operation not supported in this module."; 057 058 protected static final short DEFAULT_SOURCE_PORT = 9750; 059 060 protected static final IPProtocol DEFAULT_PROTOCOL = IPProtocol.TCP; 061 062 // Variables 063 protected Inet4Address ipAddress; 064 065 protected int sourcePort = DEFAULT_SOURCE_PORT; 066 067 /** 068 * Class constructor. Instantiates a new {@code IPDevice} object in 069 * the given port name and baud rate. 070 * 071 * @param port Serial port name where IP device is attached to. 072 * @param baudRate Serial port baud rate to communicate with the device. 073 * Other connection parameters will be set as default (8 074 * data bits, 1 stop bit, no parity, no flow control). 075 * 076 * @throws IllegalArgumentException if {@code baudRate < 0}. 077 * @throws NullPointerException if {@code port == null}. 078 * 079 * @see #IPDevice(IConnectionInterface) 080 * @see #IPDevice(String, SerialPortParameters) 081 * @see #IPDevice(String, int, int, int, int, int) 082 */ 083 protected IPDevice(String port, int baudRate) { 084 this(XBee.createConnectiontionInterface(port, baudRate)); 085 } 086 087 /** 088 * Class constructor. Instantiates a new {@code IPDevice} object in 089 * the given serial port name and settings. 090 * 091 * @param port Serial port name where IP device is attached to. 092 * @param baudRate Serial port baud rate to communicate with the device. 093 * @param dataBits Serial port data bits. 094 * @param stopBits Serial port data bits. 095 * @param parity Serial port data bits. 096 * @param flowControl Serial port data bits. 097 * 098 * @throws IllegalArgumentException if {@code baudRate < 0} or 099 * if {@code dataBits < 0} or 100 * if {@code stopBits < 0} or 101 * if {@code parity < 0} or 102 * if {@code flowControl < 0}. 103 * @throws NullPointerException if {@code port == null}. 104 * 105 * @see #IPDevice(IConnectionInterface) 106 * @see #IPDevice(String, int) 107 * @see #IPDevice(String, SerialPortParameters) 108 */ 109 protected IPDevice(String port, int baudRate, int dataBits, int stopBits, int parity, int flowControl) { 110 this(port, new SerialPortParameters(baudRate, dataBits, stopBits, parity, flowControl)); 111 } 112 113 /** 114 * Class constructor. Instantiates a new {@code IPDevice} object in 115 * the given serial port name and parameters. 116 * 117 * @param port Serial port name where IP device is attached to. 118 * @param serialPortParameters Object containing the serial port parameters. 119 * 120 * @throws NullPointerException if {@code port == null} or 121 * if {@code serialPortParameters == null}. 122 * 123 * @see #IPDevice(IConnectionInterface) 124 * @see #IPDevice(String, int) 125 * @see #IPDevice(String, int, int, int, int, int) 126 * @see com.digi.xbee.api.connection.serial.SerialPortParameters 127 */ 128 protected IPDevice(String port, SerialPortParameters serialPortParameters) { 129 this(XBee.createConnectiontionInterface(port, serialPortParameters)); 130 } 131 132 /** 133 * Class constructor. Instantiates a new {@code IPDevice} object with 134 * the given connection interface. 135 * 136 * @param connectionInterface The connection interface with the physical 137 * IP device. 138 * 139 * @throws NullPointerException if {@code connectionInterface == null} 140 * 141 * @see #IPDevice(String, int) 142 * @see #IPDevice(String, SerialPortParameters) 143 * @see #IPDevice(String, int, int, int, int, int) 144 * @see com.digi.xbee.api.connection.IConnectionInterface 145 */ 146 protected IPDevice(IConnectionInterface connectionInterface) { 147 super(connectionInterface); 148 } 149 150 151 /** 152 * @deprecated This protocol does not support the network functionality. 153 */ 154 @Override 155 public XBeeNetwork getNetwork() { 156 // IP modules do not have a network of devices. 157 return null; 158 } 159 160 /* 161 * (non-Javadoc) 162 * @see com.digi.xbee.api.AbstractXBeeDevice#readDeviceInfo() 163 */ 164 @Override 165 public void readDeviceInfo() throws TimeoutException, XBeeException { 166 super.readDeviceInfo(); 167 168 // Read the module's IP address. 169 byte[] response = getParameter("MY"); 170 try { 171 ipAddress = (Inet4Address) Inet4Address.getByAddress(response); 172 } catch (UnknownHostException e) { 173 throw new XBeeException(e); 174 } 175 // Read the source port. 176 try { 177 response = getParameter("C0"); 178 sourcePort = ByteUtils.byteArrayToInt(response); 179 } catch (TimeoutException e) { 180 // Do not refresh the source port value if there is an error reading 181 // it from the module. 182 } catch (XBeeException e) { 183 // Do not refresh the source port value if there is an error reading 184 // it from the module. 185 } 186 } 187 188 /** 189 * Returns the IP address of this IP device. 190 * 191 * <p>To refresh this value use the {@link #readDeviceInfo()} method.</p> 192 * 193 * @return The IP address of this IP device. 194 * 195 * @see java.net.Inet4Address 196 */ 197 public Inet4Address getIPAddress() { 198 return ipAddress; 199 } 200 201 /** 202 * Sets the destination IP address. 203 * 204 * @param address Destination IP address. 205 * 206 * @throws NullPointerException if {@code address == null}. 207 * @throws TimeoutException if there is a timeout setting the destination 208 * address. 209 * @throws XBeeException if there is any other XBee related exception. 210 * 211 * @see #getDestinationIPAddress() 212 * @see java.net.Inet4Address 213 */ 214 public void setDestinationIPAddress(Inet4Address address) throws TimeoutException, XBeeException { 215 if (address == null) 216 throw new NullPointerException("Destination IP address cannot be null."); 217 218 setParameter("DL", address.getAddress()); 219 } 220 221 /** 222 * Returns the destination IP address. 223 * 224 * @return The configured destination IP address. 225 * 226 * @throws TimeoutException if there is a timeout reading the destination 227 * address. 228 * @throws XBeeException if there is any other XBee related exception. 229 * 230 * @see #setDestinationIPAddress(Inet4Address) 231 * @see java.net.Inet4Address 232 */ 233 public Inet4Address getDestinationIPAddress() throws TimeoutException, XBeeException { 234 try { 235 return (Inet4Address) Inet4Address.getByAddress(getParameter("DL")); 236 } catch (UnknownHostException e) { 237 throw new XBeeException(e); 238 } 239 } 240 241 /** 242 * @deprecated This protocol does not have an associated IPv6 address. 243 */ 244 @Override 245 public Inet6Address getIPv6Address() { 246 return null; 247 } 248 249 /** 250 * @deprecated Operation not supported in this protocol. This method 251 * will raise an {@link UnsupportedOperationException}. 252 */ 253 @Override 254 public Inet6Address getIPv6DestinationAddress() 255 throws TimeoutException, XBeeException { 256 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 257 } 258 259 /** 260 * @deprecated Operation not supported in this protocol. This method 261 * will raise an {@link UnsupportedOperationException}. 262 */ 263 @Override 264 public void setIPv6DestinationAddress(Inet6Address ipv6Address) 265 throws TimeoutException, XBeeException { 266 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 267 } 268 269 /** 270 * @deprecated This protocol does not have an associated 16-bit address. 271 */ 272 @Override 273 public XBee16BitAddress get16BitAddress() { 274 // IP modules do not have 16-bit address. 275 return null; 276 } 277 278 /** 279 * @deprecated Operation not supported in this protocol. Use 280 * {@link #getDestinationIPAddress()} instead. 281 * This method will raise an 282 * {@link UnsupportedOperationException}. 283 */ 284 @Override 285 public XBee64BitAddress getDestinationAddress() throws TimeoutException, 286 XBeeException { 287 // Not supported in IP modules. 288 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 289 } 290 291 /** 292 * @deprecated Operation not supported in this protocol. Use 293 * {@link #setDestinationIPAddress(Inet4Address)} instead. 294 * This method will raise an 295 * {@link UnsupportedOperationException}. 296 */ 297 @Override 298 public void setDestinationAddress(XBee64BitAddress xbee64BitAddress) 299 throws TimeoutException, XBeeException { 300 // Not supported in IP modules. 301 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 302 } 303 304 /** 305 * @deprecated Operation not supported in this protocol. This method will 306 * raise an {@link UnsupportedOperationException}. 307 */ 308 @Override 309 public byte[] getPANID() throws TimeoutException, XBeeException { 310 // Not supported in IP modules. 311 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 312 } 313 314 /** 315 * @deprecated Operation not supported in this protocol. This method will 316 * raise an {@link UnsupportedOperationException}. 317 */ 318 @Override 319 public void setPANID(byte[] panID) throws TimeoutException, XBeeException { 320 // Not supported in IP modules. 321 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 322 } 323 324 /** 325 * @deprecated Operation not supported in this protocol. This method will 326 * raise an {@link UnsupportedOperationException}. 327 */ 328 @Override 329 public void addDataListener(IDataReceiveListener listener) { 330 // Not supported in IP modules. 331 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 332 } 333 334 /** 335 * @deprecated Operation not supported in this protocol. This method will 336 * raise an {@link UnsupportedOperationException}. 337 */ 338 @Override 339 public void removeDataListener(IDataReceiveListener listener) { 340 // Not supported in IP modules. 341 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 342 } 343 344 /** 345 * @deprecated Operation not supported in this protocol. This method will 346 * raise an {@link UnsupportedOperationException}. 347 */ 348 @Override 349 public XBeeMessage readData() { 350 // Not supported in IP modules. 351 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 352 } 353 354 /** 355 * @deprecated Operation not supported in this protocol. This method will 356 * raise an {@link UnsupportedOperationException}. 357 */ 358 @Override 359 public XBeeMessage readData(int timeout) { 360 // Not supported in IP modules. 361 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 362 } 363 364 /** 365 * @deprecated Operation not supported in this protocol. This method will 366 * raise an {@link UnsupportedOperationException}. 367 */ 368 @Override 369 public XBeeMessage readDataFrom(RemoteXBeeDevice remoteXBeeDevice) { 370 // Not supported in IP modules. 371 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 372 } 373 374 /** 375 * @deprecated Operation not supported in this protocol. This method will 376 * raise an {@link UnsupportedOperationException}. 377 */ 378 @Override 379 public XBeeMessage readDataFrom(RemoteXBeeDevice remoteXBeeDevice, 380 int timeout) { 381 // Not supported in IP modules. 382 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 383 } 384 385 /** 386 * @deprecated Operation not supported in this protocol. This method will 387 * raise an {@link UnsupportedOperationException}. 388 */ 389 @Override 390 public void sendBroadcastData(byte[] data) throws TimeoutException, 391 XBeeException { 392 // Not supported in IP modules. 393 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 394 } 395 396 /** 397 * @deprecated Operation not supported in this protocol. This method will 398 * raise an {@link UnsupportedOperationException}. 399 */ 400 @Override 401 public void sendData(RemoteXBeeDevice remoteXBeeDevice, byte[] data) 402 throws TimeoutException, XBeeException { 403 // Not supported in IP modules. 404 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 405 } 406 407 /** 408 * @deprecated Operation not supported in this protocol. This method will 409 * raise an {@link UnsupportedOperationException}. 410 */ 411 @Override 412 public void sendDataAsync(RemoteXBeeDevice remoteXBeeDevice, byte[] data) 413 throws XBeeException { 414 // Not supported in IP modules. 415 throw new UnsupportedOperationException(OPERATION_EXCEPTION); 416 } 417 418 /* 419 * (non-Javadoc) 420 * @see com.digi.xbee.api.AbstractXBeeDevice#addIPDataListener(com.digi.xbee.api.listeners.IIPDataReceiveListener) 421 */ 422 @Override 423 public void addIPDataListener(IIPDataReceiveListener listener) { 424 super.addIPDataListener(listener); 425 } 426 427 /* 428 * (non-Javadoc) 429 * @see com.digi.xbee.api.AbstractXBeeDevice#removeIPDataListener(com.digi.xbee.api.listeners.IIPDataReceiveListener) 430 */ 431 @Override 432 public void removeIPDataListener(IIPDataReceiveListener listener) { 433 super.removeIPDataListener(listener); 434 } 435 436 /** 437 * Starts listening for incoming IP transmissions in the provided port. 438 * 439 * @param sourcePort Port to listen for incoming transmissions. 440 * 441 * @throws IllegalArgumentException if {@code sourcePort < 0} or 442 * if {@code sourcePort > 65535}. 443 * @throws TimeoutException if there is a timeout setting the source port. 444 * @throws XBeeException if there is any error setting the source port. 445 * 446 * @see #stopListening() 447 */ 448 public void startListening(int sourcePort) throws TimeoutException, XBeeException { 449 if (sourcePort < 0 || sourcePort > 65535) 450 throw new IllegalArgumentException("Source port must be between 0 and 65535."); 451 452 setParameter("C0", ByteUtils.shortToByteArray((short)sourcePort)); 453 this.sourcePort = sourcePort; 454 } 455 456 /** 457 * Stops listening for incoming IP transmissions. 458 * 459 * @throws TimeoutException if there is a timeout processing the operation. 460 * @throws XBeeException if there is any other XBee related exception. 461 * 462 * @see #startListening(int) 463 */ 464 public void stopListening() throws TimeoutException, XBeeException { 465 setParameter("C0", ByteUtils.shortToByteArray((short)0)); 466 sourcePort = 0; 467 } 468 469 /** 470 * Sends the provided IP data to the given IP address and port using 471 * the specified IP protocol. For TCP and TCP SSL protocols, you can 472 * also indicate if the socket should be closed when data is sent. 473 * 474 * <p>This method blocks till a success or error response arrives or the 475 * configured receive timeout expires.</p> 476 * 477 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 478 * method and can be consulted with {@code getReceiveTimeout} method.</p> 479 * 480 * <p>For non-blocking operations use the method 481 * {@link #sendIPDataAsync(Inet4Address, int, IPProtocol, byte[])}.</p> 482 * 483 * @param ipAddress The IP address to send IP data to. 484 * @param destPort The destination port of the transmission. 485 * @param protocol The IP protocol used for the transmission. 486 * @param closeSocket {@code true} to close the socket just after the 487 * transmission. {@code false} to keep it open. 488 * @param data Byte array containing the IP data to be sent. 489 * 490 * @throws IllegalArgumentException if {@code destPort < 0} or 491 * if {@code destPort > 65535} 492 * @throws InterfaceNotOpenException if this device connection is not open. 493 * @throws NullPointerException if {@code ipAddress == null} or 494 * if {@code protocol == null} or 495 * if {@code data == null}. 496 * @throws TimeoutException if there is a timeout sending the data. 497 * @throws XBeeException if there is any other XBee related exception. 498 * 499 * @see #getReceiveTimeout() 500 * @see #sendBroadcastIPData(int, byte[]) 501 * @see #sendIPData(Inet4Address, int, IPProtocol, byte[]) 502 * @see #sendIPDataAsync(Inet4Address, int, IPProtocol, byte[]) 503 * @see #sendIPDataAsync(Inet4Address, int, IPProtocol, boolean, byte[]) 504 * @see #setReceiveTimeout(int) 505 * @see com.digi.xbee.api.models.IPProtocol 506 * @see java.net.Inet4Address 507 */ 508 public void sendIPData(Inet4Address ipAddress, int destPort, 509 IPProtocol protocol, boolean closeSocket, byte[] data) 510 throws TimeoutException, XBeeException { 511 sendIPDataImpl(ipAddress, destPort, protocol, closeSocket, data); 512 } 513 514 /** 515 * Sends the provided IP data to the given IP address and port using 516 * the specified IP protocol. 517 * 518 * <p>This method blocks till a success or error response arrives or the 519 * configured receive timeout expires.</p> 520 * 521 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 522 * method and can be consulted with {@code getReceiveTimeout} method.</p> 523 * 524 * <p>For non-blocking operations use the method 525 * {@link #sendIPDataAsync(Inet4Address, int, IPProtocol, byte[])}.</p> 526 * 527 * @param ipAddress The IP address to send IP data to. 528 * @param destPort The destination port of the transmission. 529 * @param protocol The IP protocol used for the transmission. 530 * @param data Byte array containing the IP data to be sent. 531 * 532 * @throws IllegalArgumentException if {@code destPort < 0} or 533 * if {@code destPort > 65535} 534 * @throws InterfaceNotOpenException if this device connection is not open. 535 * @throws NullPointerException if {@code ipAddress == null} or 536 * if {@code protocol == null} or 537 * if {@code data == null}. 538 * @throws TimeoutException if there is a timeout sending the data. 539 * @throws XBeeException if there is any other XBee related exception. 540 * 541 * @see #getReceiveTimeout() 542 * @see #sendBroadcastIPData(int, byte[]) 543 * @see #sendIPData(Inet4Address, int, IPProtocol, boolean, byte[]) 544 * @see #sendIPDataAsync(Inet4Address, int, IPProtocol, byte[]) 545 * @see #sendIPDataAsync(Inet4Address, int, IPProtocol, boolean, byte[]) 546 * @see #setReceiveTimeout(int) 547 * @see com.digi.xbee.api.models.IPProtocol 548 * @see java.net.Inet4Address 549 */ 550 public void sendIPData(Inet4Address ipAddress, int destPort, IPProtocol protocol, byte[] data) 551 throws TimeoutException, XBeeException { 552 sendIPDataImpl(ipAddress, destPort, protocol, false, data); 553 } 554 555 /** 556 * Sends the provided IP data to the given IP address and port 557 * asynchronously using the specified IP protocol. For TCP and TCP SSL 558 * protocols, you can also indicate if the socket should be closed when 559 * data is sent. 560 * 561 * <p>Asynchronous transmissions do not wait for answer from the remote 562 * device or for transmit status packet.</p> 563 * 564 * @param ipAddress The IP address to send IP data to. 565 * @param destPort The destination port of the transmission. 566 * @param protocol The IP protocol used for the transmission. 567 * @param closeSocket {@code true} to close the socket just after the 568 * transmission. {@code false} to keep it open. 569 * @param data Byte array containing the IP data to be sent. 570 * 571 * @throws IllegalArgumentException if {@code destPort < 0} or 572 * if {@code destPort > 65535} 573 * @throws InterfaceNotOpenException if this device connection is not open. 574 * @throws NullPointerException if {@code ipAddress == null} or 575 * if {@code protocol == null} or 576 * if {@code data == null}. 577 * @throws TimeoutException if there is a timeout sending the data. 578 * @throws XBeeException if there is any other XBee related exception. 579 * 580 * @see #sendBroadcastIPData(int, byte[]) 581 * @see #sendIPData(Inet4Address, int, IPProtocol, byte[]) 582 * @see #sendIPData(Inet4Address, int, IPProtocol, boolean, byte[]) 583 * @see #sendIPDataAsync(Inet4Address, int, IPProtocol, byte[]) 584 * @see com.digi.xbee.api.models.IPProtocol 585 * @see java.net.Inet4Address 586 */ 587 public void sendIPDataAsync(Inet4Address ipAddress, int destPort, 588 IPProtocol protocol, boolean closeSocket, byte[] data) throws XBeeException { 589 sendIPDataAsyncImpl(ipAddress, destPort, protocol, closeSocket, data); 590 } 591 592 /** 593 * Sends the provided IP data to the given IP address and port 594 * asynchronously. 595 * 596 * <p>Asynchronous transmissions do not wait for answer from the remote 597 * device or for transmit status packet.</p> 598 * 599 * @param ipAddress The IP address to send IP data to. 600 * @param destPort The destination port of the transmission. 601 * @param protocol The IP protocol used for the transmission. 602 * @param data Byte array containing the IP data to be sent. 603 * 604 * @throws IllegalArgumentException if {@code destPort < 0} or 605 * if {@code destPort > 65535} 606 * @throws InterfaceNotOpenException if this device connection is not open. 607 * @throws NullPointerException if {@code ipAddress == null} or 608 * if {@code protocol == null} or 609 * if {@code data == null}. 610 * @throws TimeoutException if there is a timeout sending the data. 611 * @throws XBeeException if there is any other XBee related exception. 612 * 613 * @see #sendBroadcastIPData(int, byte[]) 614 * @see #sendIPData(Inet4Address, int, IPProtocol, byte[]) 615 * @see #sendIPData(Inet4Address, int, IPProtocol, boolean, byte[]) 616 * @see #sendIPDataAsync(Inet4Address, int, IPProtocol, boolean, byte[]) 617 * @see com.digi.xbee.api.models.IPProtocol 618 * @see java.net.Inet4Address 619 */ 620 public void sendIPDataAsync(Inet4Address ipAddress, int destPort, 621 IPProtocol protocol, byte[] data) throws TimeoutException, XBeeException { 622 sendIPDataAsyncImpl(ipAddress, destPort, protocol, false, data); 623 } 624 625 /** 626 * Sends the provided IP data to all clients. 627 * 628 * <p>This method blocks till a success or error transmit status arrives or 629 * the configured receive timeout expires.</p> 630 * 631 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 632 * method and can be consulted with {@code getReceiveTimeout} method.</p> 633 * 634 * @param destPort The destination port of the transmission. 635 * @param data Byte array containing the IP data to be sent. 636 * 637 * @throws IllegalArgumentException if {@code destPort < 0} or 638 * if {@code destPort > 65535} 639 * @throws InterfaceNotOpenException if this device connection is not open. 640 * @throws NullPointerException if {@code data == null}. 641 * @throws TimeoutException if there is a timeout sending the data. 642 * @throws XBeeException if there is any other XBee related exception. 643 * 644 * @see #getReceiveTimeout() 645 * @see #sendIPData(Inet4Address, int, IPProtocol, byte[]) 646 * @see #sendIPData(Inet4Address, int, IPProtocol, boolean, byte[]) 647 * @see #sendIPDataAsync(Inet4Address, int, IPProtocol, byte[]) 648 * @see #sendIPDataAsync(Inet4Address, int, IPProtocol, boolean, byte[]) 649 * @see #setReceiveTimeout(int) 650 */ 651 public void sendBroadcastIPData(int destPort, byte[] data) throws TimeoutException, XBeeException { 652 try { 653 sendIPData((Inet4Address) Inet4Address.getByName(BROADCAST_IP), destPort, IPProtocol.UDP, false, data); 654 } catch (UnknownHostException e) { 655 throw new XBeeException(e); 656 } 657 } 658 659 /** 660 * Reads new IP data received by this XBee device during the 661 * configured receive timeout. 662 * 663 * <p>This method blocks until new IP data is received or the 664 * configured receive timeout expires.</p> 665 * 666 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 667 * method and can be consulted with {@code getReceiveTimeout} method.</p> 668 * 669 * <p>For non-blocking operations, register a {@code IIPDataReceiveListener} 670 * using the method {@link #addIPDataListener(IIPDataReceiveListener)}.</p> 671 * 672 * <p>Before reading IP data you need to start listening for incoming 673 * IP data at a specific port. Use the {@code startListening} method 674 * for that purpose. When finished, you can use the {@code stopListening} 675 * method to stop listening for incoming IP data.</p> 676 * 677 * @return A {@code IPMessage} object containing the IP data and 678 * the IP address that sent the data. {@code null} if this did not 679 * receive new IP data during the configured receive timeout. 680 * 681 * @throws InterfaceNotOpenException if this device connection is not open. 682 * 683 * @see #getReceiveTimeout() 684 * @see #readIPData(int) 685 * @see #readIPDataFrom(Inet4Address) 686 * @see #readIPDataFrom(Inet4Address, int) 687 * @see #setReceiveTimeout(int) 688 * @see #startListening(int) 689 * @see #stopListening() 690 * @see com.digi.xbee.api.models.IPMessage 691 */ 692 public IPMessage readIPData() { 693 return readIPDataPacket(null, TIMEOUT_READ_PACKET); 694 } 695 696 /** 697 * Reads new IP data received by this XBee device during the provided 698 * timeout. 699 * 700 * <p>This method blocks until new IP data is received or the provided 701 * timeout expires.</p> 702 * 703 * <p>For non-blocking operations, register a {@code IIPDataReceiveListener} 704 * using the method {@link #addIPDataListener(IIPDataReceiveListener)}.</p> 705 * 706 * <p>Before reading IP data you need to start listening for incoming 707 * IP data at a specific port. Use the {@code startListening} method 708 * for that purpose. When finished, you can use the {@code stopListening} 709 * method to stop listening for incoming IP data.</p> 710 * 711 * @param timeout The time to wait for new IP data in milliseconds. 712 * 713 * @return A {@code IPMessage} object containing the data and the IP 714 * address that sent the data. {@code null} if this device did not 715 * receive new data during {@code timeout} milliseconds. 716 * 717 * @throws IllegalArgumentException if {@code timeout < 0}. 718 * @throws InterfaceNotOpenException if this device connection is not open. 719 * 720 * @see #readIPData() 721 * @see #readIPDataFrom(Inet4Address) 722 * @see #readIPDataFrom(Inet4Address, int) 723 * @see #startListening(int) 724 * @see #stopListening() 725 * @see com.digi.xbee.api.models.IPMessage 726 */ 727 public IPMessage readIPData(int timeout) { 728 if (timeout < 0) 729 throw new IllegalArgumentException("Read timeout must be 0 or greater."); 730 731 return readIPDataPacket(null, timeout); 732 } 733 734 /** 735 * Reads new IP data received from the given IP address during the 736 * configured receive timeout. 737 * 738 * <p>This method blocks until new data from the provided IP address is 739 * received or the configured receive timeout expires.</p> 740 * 741 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 742 * method and can be consulted with {@code getReceiveTimeout} method.</p> 743 * 744 * <p>For non-blocking operations, register a {@code IIPDataReceiveListener} 745 * using the method {@link #addIPDataListener(IIPDataReceiveListener)}.</p> 746 * 747 * <p>Before reading IP data you need to start listening for incoming 748 * IP data at a specific port. Use the {@code startListening} method 749 * for that purpose. When finished, you can use the {@code stopListening} 750 * method to stop listening for incoming IP data.</p> 751 * 752 * @param ipAddress The IP address to read data from. 753 * 754 * @return A {@code IPMessage} object containing the IP data and 755 * the IP address of the remote node that sent the data. 756 * {@code null} if this device did not receive new IP data 757 * from the provided IP address during the configured receive 758 * timeout. 759 * 760 * @throws InterfaceNotOpenException if this device connection is not open. 761 * @throws NullPointerException if {@code ipAddress == null}. 762 * 763 * @see #getReceiveTimeout() 764 * @see #readIPData() 765 * @see #readIPData(int) 766 * @see #readIPDataFrom(Inet4Address, int) 767 * @see #setReceiveTimeout(int) 768 * @see #startListening(int) 769 * @see #stopListening() 770 * @see com.digi.xbee.api.models.IPMessage 771 * @see java.net.Inet4Address 772 */ 773 public IPMessage readIPDataFrom(Inet4Address ipAddress) { 774 if (ipAddress == null) 775 throw new NullPointerException("IP address cannot be null."); 776 777 return readIPDataPacket(ipAddress, TIMEOUT_READ_PACKET); 778 } 779 780 /** 781 * Reads new IP data received from the given IP address during the 782 * provided timeout. 783 * 784 * <p>This method blocks until new IP data from the provided IP 785 * address is received or the given timeout expires.</p> 786 * 787 * <p>For non-blocking operations, register a {@code IIPDataReceiveListener} 788 * using the method {@link #addIPDataListener(IIPDataReceiveListener)}.</p> 789 * 790 * <p>Before reading IP data you need to start listening for incoming 791 * IP data at a specific port. Use the {@code startListening} method 792 * for that purpose. When finished, you can use the {@code stopListening} 793 * method to stop listening for incoming IP data.</p> 794 * 795 * @param ipAddress The IP address to read data from. 796 * @param timeout The time to wait for new IP data in milliseconds. 797 * 798 * @return An {@code IPMessage} object containing the IP data and 799 * the IP address that sent the data. {@code null} if this device 800 * did not receive new IP data from the provided IP address 801 * during {@code timeout} milliseconds. 802 * 803 * @throws IllegalArgumentException if {@code timeout < 0}. 804 * @throws InterfaceNotOpenException if this device connection is not open. 805 * @throws NullPointerException if {@code ipAddress == null}. 806 * 807 * @see #readIPDataFrom(Inet4Address) 808 * @see #readIPData() 809 * @see #readIPData(int) 810 * @see #startListening(int) 811 * @see #stopListening() 812 * @see com.digi.xbee.api.models.IPMessage 813 * @see java.net.Inet4Address 814 */ 815 public IPMessage readIPDataFrom(Inet4Address ipAddress, int timeout) { 816 if (ipAddress == null) 817 throw new NullPointerException("IP address cannot be null."); 818 if (timeout < 0) 819 throw new IllegalArgumentException("Read timeout must be 0 or greater."); 820 821 return readIPDataPacket(ipAddress, timeout); 822 } 823 824 /** 825 * Reads a new IP data packet received by this IP XBee device during 826 * the provided timeout. 827 * 828 * <p>This method blocks until new IP data is received or the given 829 * timeout expires.</p> 830 * 831 * <p>If the provided IP address is {@code null} the method returns 832 * the first IP data packet read from any IP address. 833 * <br> 834 * If the IP address is not {@code null} the method returns the first 835 * data package read from the provided IP address. 836 * </p> 837 * 838 * @param remoteIPAddress The IP address to get a IP data packet from. 839 * {@code null} to read a IP data packet from 840 * any IP address. 841 * @param timeout The time to wait for a IP data packet in milliseconds. 842 * 843 * @return A {@code IPMessage} received by this device, containing the 844 * data and the source IP address that sent the IP data. 845 * {@code null} if this device did not receive new IP data 846 * during {@code timeout} milliseconds, or if any error occurs while 847 * trying to get the source of the message. 848 * 849 * @throws InterfaceNotOpenException if this device connection is not open. 850 * 851 * @see com.digi.xbee.api.models.XBeeMessage 852 * @see java.net.Inet4Address 853 */ 854 private IPMessage readIPDataPacket(Inet4Address remoteIPAddress, int timeout) { 855 // Check connection. 856 if (!connectionInterface.isOpen()) 857 throw new InterfaceNotOpenException(); 858 859 XBeePacketsQueue xbeePacketsQueue = dataReader.getXBeePacketsQueue(); 860 XBeePacket xbeePacket = null; 861 862 if (remoteIPAddress != null) 863 xbeePacket = xbeePacketsQueue.getFirstIPDataPacketFrom(remoteIPAddress, timeout); 864 else 865 xbeePacket = xbeePacketsQueue.getFirstIPDataPacket(timeout); 866 867 if (xbeePacket == null) 868 return null; 869 870 // Obtain the data and IP address from the packet. 871 byte[] data = null; 872 Inet4Address ipAddress = null; 873 int sourcePort; 874 int destPort; 875 IPProtocol protocol = IPProtocol.TCP; 876 877 switch (((XBeeAPIPacket)xbeePacket).getFrameType()) { 878 case RX_IPV4: 879 RXIPv4Packet receivePacket = (RXIPv4Packet)xbeePacket; 880 data = receivePacket.getData(); 881 ipAddress = receivePacket.getSourceAddress(); 882 sourcePort = receivePacket.getSourcePort(); 883 destPort = receivePacket.getDestPort(); 884 break; 885 default: 886 return null; 887 } 888 889 // Create and return the IP message. 890 return new IPMessage(ipAddress, sourcePort, destPort, protocol, data); 891 } 892 893 /** 894 * Sends the provided IP data to the given IP address and port using 895 * the specified IP protocol. For TCP and TCP SSL protocols, you can 896 * also indicate if the socket should be closed when data is sent. 897 * 898 * <p>This method blocks till a success or error response arrives or the 899 * configured receive timeout expires.</p> 900 * 901 * <p>The receive timeout is configured using the {@code setReceiveTimeout} 902 * method and can be consulted with {@code getReceiveTimeout} method.</p> 903 * 904 * @param ipAddress The IP address to send IP data to. 905 * @param destPort The destination port of the transmission. 906 * @param protocol The IP protocol used for the transmission. 907 * @param closeSocket {@code true} to close the socket just after the 908 * transmission. {@code false} to keep it open. 909 * @param data Byte array containing the IP data to be sent. 910 * 911 * @throws IllegalArgumentException if {@code destPort < 0} or 912 * if {@code destPort > 65535} 913 * @throws InterfaceNotOpenException if this device connection is not open. 914 * @throws NullPointerException if {@code ipAddress == null} or 915 * if {@code protocol == null} or 916 * if {@code data == null}. 917 * @throws TimeoutException if there is a timeout sending the data. 918 * @throws XBeeException if there is any other XBee related exception. 919 * 920 * @see #getReceiveTimeout() 921 * @see #sendBroadcastIPData(int, byte[]) 922 * @see #sendIPData(Inet4Address, int, IPProtocol, byte[]) 923 * @see #sendIPData(Inet4Address, int, IPProtocol, boolean, byte[]) 924 * @see #sendIPDataAsync(Inet4Address, int, IPProtocol, byte[]) 925 * @see #sendIPDataAsync(Inet4Address, int, IPProtocol, boolean, byte[]) 926 * @see #setReceiveTimeout(int) 927 * @see com.digi.xbee.api.models.IPProtocol 928 * @see java.net.Inet4Address 929 */ 930 private void sendIPDataImpl(Inet4Address ipAddress, int destPort, 931 IPProtocol protocol, boolean closeSocket, byte[] data) 932 throws TimeoutException, XBeeException { 933 if (ipAddress == null) 934 throw new NullPointerException("IP address cannot be null"); 935 if (protocol == null) 936 throw new NullPointerException("Protocol cannot be null"); 937 if (data == null) 938 throw new NullPointerException("Data cannot be null"); 939 940 if (destPort < 0 || destPort > 65535) 941 throw new IllegalArgumentException("Destination port must be between 0 and 65535."); 942 943 // Check if device is remote. 944 if (isRemote()) 945 throw new OperationNotSupportedException("Cannot send IP data from a remote device."); 946 947 // The source port value depends on the protocol used in the transmission. For UDP, source port 948 // value must be the same as 'C0' one. For TCP it must be 0. 949 int sourcePort = this.sourcePort; 950 if (protocol != IPProtocol.UDP) 951 sourcePort = 0; 952 953 logger.debug(toString() + "Sending IP data to {}:{} >> {}.", ipAddress, destPort, HexUtils.prettyHexString(data)); 954 955 XBeePacket xbeePacket = new TXIPv4Packet(getNextFrameID(), ipAddress, destPort, 956 sourcePort, protocol, closeSocket ? TXIPv4Packet.OPTIONS_CLOSE_SOCKET: TXIPv4Packet.OPTIONS_LEAVE_SOCKET_OPEN, data); 957 958 sendAndCheckXBeePacket(xbeePacket, false); 959 } 960 961 /** 962 * Sends the provided IP data to the given IP address and port 963 * asynchronously using the specified IP protocol. For TCP and TCP SSL 964 * protocols, you can also indicate if the socket should be closed when 965 * data is sent. 966 * 967 * <p>Asynchronous transmissions do not wait for answer from the remote 968 * device or for transmit status packet.</p> 969 * 970 * @param ipAddress The IP address to send IP data to. 971 * @param destPort The destination port of the transmission. 972 * @param protocol The IP protocol used for the transmission. 973 * @param closeSocket {@code true} to close the socket just after the 974 * transmission. {@code false} to keep it open. 975 * @param data Byte array containing the IP data to be sent. 976 * 977 * @throws IllegalArgumentException if {@code destPort < 0} or 978 * if {@code destPort > 65535} 979 * @throws InterfaceNotOpenException if this device connection is not open. 980 * @throws NullPointerException if {@code ipAddress == null} or 981 * if {@code protocol == null} or 982 * if {@code data == null}. 983 * @throws TimeoutException if there is a timeout sending the data. 984 * @throws XBeeException if there is any other XBee related exception. 985 * 986 * @see #sendBroadcastIPData(int, byte[]) 987 * @see #sendIPData(Inet4Address, int, IPProtocol, byte[]) 988 * @see #sendIPData(Inet4Address, int, IPProtocol, boolean, byte[]) 989 * @see #sendIPDataAsync(Inet4Address, int, IPProtocol, byte[]) 990 * @see #sendIPDataAsync(Inet4Address, int, IPProtocol, boolean, byte[]) 991 * @see com.digi.xbee.api.models.IPProtocol 992 * @see java.net.Inet4Address 993 */ 994 private void sendIPDataAsyncImpl(Inet4Address ipAddress, int destPort, 995 IPProtocol protocol, boolean closeSocket, byte[] data) throws XBeeException { 996 if (ipAddress == null) 997 throw new NullPointerException("IP address cannot be null"); 998 if (protocol == null) 999 throw new NullPointerException("Protocol cannot be null"); 1000 if (data == null) 1001 throw new NullPointerException("Data cannot be null"); 1002 if (destPort < 0 || destPort > 65535) 1003 throw new IllegalArgumentException("Destination port must be between 0 and 65535."); 1004 1005 // Check if device is remote. 1006 if (isRemote()) 1007 throw new OperationNotSupportedException("Cannot send IP data from a remote device."); 1008 1009 // The source port value depends on the protocol used in the transmission. For UDP, source port 1010 // value must be the same as 'C0' one. For TCP it must be 0. 1011 int sourcePort = this.sourcePort; 1012 if (protocol != IPProtocol.UDP) 1013 sourcePort = 0; 1014 1015 logger.debug(toString() + "Sending IP data asynchronously to {}:{} >> {}.", ipAddress, destPort, HexUtils.prettyHexString(data)); 1016 1017 XBeePacket xbeePacket = new TXIPv4Packet(getNextFrameID(), ipAddress, destPort, sourcePort, 1018 protocol, closeSocket ? TXIPv4Packet.OPTIONS_CLOSE_SOCKET: TXIPv4Packet.OPTIONS_LEAVE_SOCKET_OPEN, data); 1019 1020 sendAndCheckXBeePacket(xbeePacket, true); 1021 } 1022}