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