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}