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