001/**
002 * Copyright (c) 2014-2015 Digi International Inc.,
003 * All rights not expressly granted are reserved.
004 *
005 * This Source Code Form is subject to the terms of the Mozilla Public
006 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
007 * You can obtain one at http://mozilla.org/MPL/2.0/.
008 *
009 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
010 * =======================================================================
011 */
012package com.digi.xbee.api;
013
014import java.io.IOException;
015
016import com.digi.xbee.api.connection.DataReader;
017import com.digi.xbee.api.connection.IConnectionInterface;
018import com.digi.xbee.api.connection.serial.SerialPortParameters;
019import com.digi.xbee.api.exceptions.ATCommandException;
020import com.digi.xbee.api.exceptions.InterfaceAlreadyOpenException;
021import com.digi.xbee.api.exceptions.InterfaceNotOpenException;
022import com.digi.xbee.api.exceptions.InvalidOperatingModeException;
023import com.digi.xbee.api.exceptions.OperationNotSupportedException;
024import com.digi.xbee.api.exceptions.TimeoutException;
025import com.digi.xbee.api.exceptions.XBeeException;
026import com.digi.xbee.api.listeners.IIOSampleReceiveListener;
027import com.digi.xbee.api.listeners.IModemStatusReceiveListener;
028import com.digi.xbee.api.listeners.IPacketReceiveListener;
029import com.digi.xbee.api.listeners.IDataReceiveListener;
030import com.digi.xbee.api.models.APIOutputMode;
031import com.digi.xbee.api.models.ATCommand;
032import com.digi.xbee.api.models.ATCommandResponse;
033import com.digi.xbee.api.models.ExplicitXBeeMessage;
034import com.digi.xbee.api.models.ModemStatusEvent;
035import com.digi.xbee.api.models.OperatingMode;
036import com.digi.xbee.api.models.XBee16BitAddress;
037import com.digi.xbee.api.models.XBee64BitAddress;
038import com.digi.xbee.api.models.XBeeMessage;
039import com.digi.xbee.api.models.XBeePacketsQueue;
040import com.digi.xbee.api.models.XBeeProtocol;
041import com.digi.xbee.api.models.XBeeTransmitOptions;
042import com.digi.xbee.api.packet.APIFrameType;
043import com.digi.xbee.api.packet.XBeeAPIPacket;
044import com.digi.xbee.api.packet.XBeePacket;
045import com.digi.xbee.api.packet.common.ExplicitAddressingPacket;
046import com.digi.xbee.api.packet.common.ExplicitRxIndicatorPacket;
047import com.digi.xbee.api.packet.common.ReceivePacket;
048import com.digi.xbee.api.packet.common.TransmitPacket;
049import com.digi.xbee.api.packet.raw.RX16Packet;
050import com.digi.xbee.api.packet.raw.RX64Packet;
051import com.digi.xbee.api.packet.raw.TX64Packet;
052import com.digi.xbee.api.utils.HexUtils;
053
054/**
055 * This class represents a local XBee device.
056 * 
057 * @see DigiMeshDevice
058 * @see DigiPointDevice
059 * @see Raw802Device
060 * @see ZigBeeDevice
061 */
062public class XBeeDevice extends AbstractXBeeDevice {
063
064        // Constants.
065        private static int TIMEOUT_RESET = 5000;
066        private static int TIMEOUT_READ_PACKET = 3000;
067        
068        private static String COMMAND_MODE_CHAR = "+";
069        private static String COMMAND_MODE_OK = "OK\r";
070        
071        // Variables.
072        protected XBeeNetwork network;
073        
074        private Object resetLock = new Object();
075        
076        private boolean modemStatusReceived = false;
077        
078        /**
079         * Class constructor. Instantiates a new {@code XBeeDevice} object 
080         * physically connected to the given port name and configured at the 
081         * provided baud rate.
082         * 
083         * @param port Serial port name where XBee device is attached to.
084         * @param baudRate Serial port baud rate to communicate with the device. 
085         *                 Other connection parameters will be set as default (8 
086         *                 data bits, 1 stop bit, no parity, no flow control).
087         * 
088         * @throws IllegalArgumentException if {@code baudRate < 0}.
089         * @throws NullPointerException if {@code port == null}.
090         * 
091         * @see #XBeeDevice(IConnectionInterface)
092         * @see #XBeeDevice(String, SerialPortParameters)
093         * @see #XBeeDevice(String, int, int, int, int, int)
094         */
095        public XBeeDevice(String port, int baudRate) {
096                super(port, baudRate);
097        }
098        
099        /**
100         * Class constructor. Instantiates a new {@code XBeeDevice} object 
101         * physically connected to the given port name and configured to communicate 
102         * with the provided serial settings.
103         * 
104         * @param port Serial port name where XBee device is attached to.
105         * @param baudRate Serial port baud rate to communicate with the device.
106         * @param dataBits Serial port data bits.
107         * @param stopBits Serial port data bits.
108         * @param parity Serial port data bits.
109         * @param flowControl Serial port data bits.
110         * 
111         * @throws IllegalArgumentException if {@code baudRate < 0} or
112         *                                  if {@code dataBits < 0} or
113         *                                  if {@code stopBits < 0} or
114         *                                  if {@code parity < 0} or
115         *                                  if {@code flowControl < 0}.
116         * @throws NullPointerException if {@code port == null}.
117         * 
118         * @see #XBeeDevice(IConnectionInterface)
119         * @see #XBeeDevice(String, int)
120         * @see #XBeeDevice(String, SerialPortParameters)
121         */
122        public XBeeDevice(String port, int baudRate, int dataBits, int stopBits, int parity, int flowControl) {
123                super(port, baudRate, dataBits, stopBits, parity, flowControl);
124        }
125        
126        /**
127         * Class constructor. Instantiates a new {@code XBeeDevice} object 
128         * physically connected to the given port name and configured to communicate 
129         * with the provided serial settings.
130         * 
131         * @param port Serial port name where XBee device is attached to.
132         * @param serialPortParameters Object containing the serial port parameters.
133         * 
134         * @throws NullPointerException if {@code port == null} or
135         *                              if {@code serialPortParameters == null}.
136         * 
137         * @see #XBeeDevice(IConnectionInterface)
138         * @see #XBeeDevice(String, int)
139         * @see #XBeeDevice(String, int, int, int, int, int)
140         * @see com.digi.xbee.api.connection.serial.SerialPortParameters
141         */
142        public XBeeDevice(String port, SerialPortParameters serialPortParameters) {
143                super(port, serialPortParameters);
144        }
145        
146        /**
147         * Class constructor. Instantiates a new {@code XBeeDevice} object with the 
148         * given connection interface.
149         * 
150         * @param connectionInterface The connection interface with the physical 
151         *                            XBee device.
152         * 
153         * @throws NullPointerException if {@code connectionInterface == null}.
154         * 
155         * @see #XBeeDevice(String, int)
156         * @see #XBeeDevice(String, SerialPortParameters)
157         * @see #XBeeDevice(String, int, int, int, int, int)
158         * @see com.digi.xbee.api.connection.IConnectionInterface
159         */
160        public XBeeDevice(IConnectionInterface connectionInterface) {
161                super(connectionInterface);
162        }
163        
164        /**
165         * Opens the connection interface associated with this XBee device.
166         * 
167         * <p>When opening the device an information reading process is 
168         * automatically performed. This includes:</p>
169         * 
170         * <ul>
171         * <li>64-bit address.</li>
172         * <li>Node Identifier.</li>
173         * <li>Hardware version.</li>
174         * <li>Firmware version.</li>
175         * <li>XBee device protocol.</li>
176         * <li>16-bit address (not for DigiMesh modules).</li>
177         * </ul>
178         * 
179         * @throws InterfaceAlreadyOpenException if this device connection is 
180         *                                       already open.
181         * @throws XBeeException if there is any problem opening this device 
182         *                       connection.
183         * 
184         * @see #close()
185         * @see #isOpen()
186         */
187        public void open() throws XBeeException {
188                logger.info(toString() + "Opening the connection interface...");
189                
190                // First, verify that the connection is not already open.
191                if (connectionInterface.isOpen())
192                        throw new InterfaceAlreadyOpenException();
193                
194                // Connect the interface.
195                connectionInterface.open();
196                
197                logger.info(toString() + "Connection interface open.");
198                
199                // Initialize the data reader.
200                dataReader = new DataReader(connectionInterface, operatingMode, this);
201                dataReader.start();
202                
203                // Wait 10 milliseconds until the dataReader thread is started.
204                // This is because when the connection is opened immediately after 
205                // closing it, there is sometimes a concurrency problem and the 
206                // dataReader thread never dies.
207                try {
208                        Thread.sleep(10);
209                } catch (InterruptedException e) {}
210                
211                // Determine the operating mode of the XBee device if it is unknown.
212                if (operatingMode == OperatingMode.UNKNOWN)
213                        operatingMode = determineOperatingMode();
214                
215                // Check if the operating mode is a valid and supported one.
216                if (operatingMode == OperatingMode.UNKNOWN) {
217                        close();
218                        throw new InvalidOperatingModeException("Could not determine operating mode.");
219                } else if (operatingMode == OperatingMode.AT) {
220                        close();
221                        throw new InvalidOperatingModeException(operatingMode);
222                }
223                
224                // Read the device info (obtain its parameters and protocol).
225                try {
226                        readDeviceInfo();
227                } catch (ATCommandException e) {
228                        throw new XBeeException("Error reading device information.", e);
229                }
230        }
231        
232        /**
233         * Closes the connection interface associated with this XBee device.
234         * 
235         * @see #isOpen()
236         * @see #open()
237         */
238        public void close() {
239                // Stop XBee reader.
240                if (dataReader != null && dataReader.isRunning())
241                        dataReader.stopReader();
242                // Close interface.
243                connectionInterface.close();
244                logger.info(toString() + "Connection interface closed.");
245        }
246        
247        /**
248         * Returns whether the connection interface associated to this device is 
249         * already open.
250         * 
251         * @return {@code true} if the interface is open, {@code false} otherwise.
252         * 
253         * @see #close()
254         * @see #open()
255         */
256        public boolean isOpen() {
257                if (connectionInterface != null)
258                        return connectionInterface.isOpen();
259                return false;
260        }
261        
262        /**
263         * Always returns {@code false}, since this is always a local device.
264         * 
265         * @return {@code false} since it is a local device.
266         */
267        @Override
268        public boolean isRemote() {
269                return false;
270        }
271        
272        /**
273         * Returns the network associated with this XBee device.
274         * 
275         * @return The XBee network of the device.
276         * 
277         * @throws InterfaceNotOpenException if this device connection is not open.
278         * 
279         * @see XBeeNetwork
280         */
281        public XBeeNetwork getNetwork() {
282                if (!isOpen())
283                        throw new InterfaceNotOpenException();
284                
285                if (network == null)
286                        network = new XBeeNetwork(this);
287                return network;
288        }
289        
290        /**
291         * Returns the Operating mode (AT, API or API escaped) of this XBee device.
292         * 
293         * @return The operating mode of this XBee device.
294         * 
295         * @see com.digi.xbee.api.models.OperatingMode
296         */
297        @Override
298        public OperatingMode getOperatingMode() {
299                return super.getOperatingMode();
300        }
301        
302        /*
303         * (non-Javadoc)
304         * @see com.digi.xbee.api.AbstractXBeeDevice#getNextFrameID()
305         */
306        @Override
307        protected int getNextFrameID() {
308                return super.getNextFrameID();
309        }
310        
311        /**
312         * Returns this XBee device configured timeout for receiving packets in 
313         * synchronous operations.
314         * 
315         * @return The current receive timeout in milliseconds.
316         * 
317         * @see #setReceiveTimeout(int)
318         */
319        public int getReceiveTimeout() {
320                return receiveTimeout;
321        }
322        
323        /**
324         * Configures this XBee device timeout in milliseconds for receiving 
325         * packets in synchronous operations.
326         *  
327         * @param receiveTimeout The new receive timeout in milliseconds.
328         * 
329         * @throws IllegalArgumentException if {@code receiveTimeout < 0}.
330         * 
331         * @see #getReceiveTimeout()
332         */
333        public void setReceiveTimeout(int receiveTimeout) {
334                if (receiveTimeout < 0)
335                        throw new IllegalArgumentException("Receive timeout cannot be less than 0.");
336                
337                this.receiveTimeout = receiveTimeout;
338        }
339        
340        /**
341         * Determines the operating mode of this XBee device.
342         * 
343         * @return The operating mode of the XBee device.
344         * 
345         * @throws InterfaceNotOpenException if this device connection is not open.
346         * @throws OperationNotSupportedException if the packet is being sent from 
347         *                                        a remote device.
348         * 
349         * @see com.digi.xbee.api.models.OperatingMode
350         */
351        protected OperatingMode determineOperatingMode() throws OperationNotSupportedException {
352                try {
353                        // Check if device is in API or API Escaped operating modes.
354                        operatingMode = OperatingMode.API;
355                        dataReader.setXBeeReaderMode(operatingMode);
356                        
357                        ATCommandResponse response = sendATCommand(new ATCommand("AP"));
358                        if (response.getResponse() != null && response.getResponse().length > 0) {
359                                if (response.getResponse()[0] != OperatingMode.API.getID()) {
360                                        operatingMode = OperatingMode.API_ESCAPE;
361                                        dataReader.setXBeeReaderMode(operatingMode);
362                                }
363                                logger.debug(toString() + "Using {}.", operatingMode.getName());
364                                return operatingMode;
365                        }
366                } catch (TimeoutException e) {
367                        // Check if device is in AT operating mode.
368                        operatingMode = OperatingMode.AT;
369                        dataReader.setXBeeReaderMode(operatingMode);
370                        
371                        try {
372                                // It is necessary to wait at least 1 second to enter in 
373                                // command mode after sending any data to the device.
374                                Thread.sleep(TIMEOUT_BEFORE_COMMAND_MODE);
375                                // Try to enter in AT command mode, if so the module is in AT mode.
376                                boolean success = enterATCommandMode();
377                                if (success)
378                                        return OperatingMode.AT;
379                        } catch (TimeoutException e1) {
380                                logger.error(e1.getMessage(), e1);
381                        } catch (InvalidOperatingModeException e1) {
382                                logger.error(e1.getMessage(), e1);
383                        } catch (InterruptedException e1) {
384                                logger.error(e1.getMessage(), e1);
385                        }
386                } catch (InvalidOperatingModeException e) {
387                        logger.error("Invalid operating mode", e);
388                } catch (IOException e) {
389                        logger.error(e.getMessage(), e);
390                }
391                return OperatingMode.UNKNOWN;
392        }
393        
394        /**
395         * Attempts to put this device in AT Command mode. Only valid if device is 
396         * working in AT mode.
397         * 
398         * @return {@code true} if the device entered in AT command mode, 
399         *         {@code false} otherwise.
400         * 
401         * @throws InterfaceNotOpenException if this device connection is not open.
402         * @throws InvalidOperatingModeException if the operating mode cannot be 
403         *                                       determined or is not supported.
404         * @throws TimeoutException if the configured time for this device expires.
405         */
406        private boolean enterATCommandMode() throws InvalidOperatingModeException, TimeoutException {
407                if (!connectionInterface.isOpen())
408                        throw new InterfaceNotOpenException();
409                if (operatingMode != OperatingMode.AT)
410                        throw new InvalidOperatingModeException("Invalid mode. Command mode can be only accessed while in AT mode.");
411                
412                // Enter in AT command mode (send '+++'). The process waits 1,5 seconds for the 'OK\n'.
413                byte[] readData = new byte[256];
414                try {
415                        // Send the command mode sequence.
416                        connectionInterface.writeData(COMMAND_MODE_CHAR.getBytes());
417                        connectionInterface.writeData(COMMAND_MODE_CHAR.getBytes());
418                        connectionInterface.writeData(COMMAND_MODE_CHAR.getBytes());
419                        
420                        // Wait some time to let the module generate a response.
421                        Thread.sleep(TIMEOUT_ENTER_COMMAND_MODE);
422                        
423                        // Read data from the device (it should answer with 'OK\r').
424                        int readBytes = connectionInterface.readData(readData);
425                        if (readBytes < COMMAND_MODE_OK.length())
426                                throw new TimeoutException();
427                        
428                        // Check if the read data is 'OK\r'.
429                        String readString = new String(readData, 0, readBytes);
430                        if (!readString.contains(COMMAND_MODE_OK))
431                                return false;
432                        
433                        // Read data was 'OK\r'.
434                        return true;
435                } catch (IOException e) {
436                        logger.error(e.getMessage(), e);
437                } catch (InterruptedException e) {
438                        logger.error(e.getMessage(), e);
439                }
440                return false;
441        }
442        
443        /*
444         * (non-Javadoc)
445         * @see com.digi.xbee.api.AbstractXBeeDevice#addPacketListener(com.digi.xbee.api.listeners.IPacketReceiveListener)
446         */
447        @Override
448        public void addPacketListener(IPacketReceiveListener listener) {
449                super.addPacketListener(listener);
450        }
451        
452        /*
453         * (non-Javadoc)
454         * @see com.digi.xbee.api.AbstractXBeeDevice#removePacketListener(com.digi.xbee.api.listeners.IPacketReceiveListener)
455         */
456        @Override
457        public void removePacketListener(IPacketReceiveListener listener) {
458                super.removePacketListener(listener);
459        }
460        
461        /*
462         * (non-Javadoc)
463         * @see com.digi.xbee.api.AbstractXBeeDevice#addDataListener(com.digi.xbee.api.listeners.IDataReceiveListener)
464         */
465        @Override
466        public void addDataListener(IDataReceiveListener listener) {
467                super.addDataListener(listener);
468        }
469        
470        /*
471         * (non-Javadoc)
472         * @see com.digi.xbee.api.AbstractXBeeDevice#removeDataListener(com.digi.xbee.api.listeners.IDataReceiveListener)
473         */
474        @Override
475        public void removeDataListener(IDataReceiveListener listener) {
476                super.removeDataListener(listener);
477        }
478        
479        /*
480         * (non-Javadoc)
481         * @see com.digi.xbee.api.AbstractXBeeDevice#addIOSampleListener(com.digi.xbee.api.listeners.IIOSampleReceiveListener)
482         */
483        @Override
484        public void addIOSampleListener(IIOSampleReceiveListener listener) {
485                super.addIOSampleListener(listener);
486        }
487        
488        /*
489         * (non-Javadoc)
490         * @see com.digi.xbee.api.AbstractXBeeDevice#removeIOSampleListener(com.digi.xbee.api.listeners.IIOSampleReceiveListener)
491         */
492        @Override
493        public void removeIOSampleListener(IIOSampleReceiveListener listener) {
494                super.removeIOSampleListener(listener);
495        }
496        
497        /*
498         * (non-Javadoc)
499         * @see com.digi.xbee.api.AbstractXBeeDevice#addModemStatusListener(com.digi.xbee.api.listeners.IModemStatusReceiveListener)
500         */
501        @Override
502        public void addModemStatusListener(IModemStatusReceiveListener listener) {
503                super.addModemStatusListener(listener);
504        }
505        
506        /*
507         * (non-Javadoc)
508         * @see com.digi.xbee.api.AbstractXBeeDevice#removeModemStatusListener(com.digi.xbee.api.listeners.IModemStatusReceiveListener)
509         */
510        @Override
511        public void removeModemStatusListener(IModemStatusReceiveListener listener) {
512                super.removeModemStatusListener(listener);
513        }
514        
515        /**
516         * Sends asynchronously the provided data to the XBee device of the network 
517         * corresponding to the given 64-bit address.
518         * 
519         * <p>Asynchronous transmissions do not wait for answer from the remote 
520         * device or for transmit status packet.</p>
521         * 
522         * @param address The 64-bit address of the XBee that will receive the data.
523         * @param data Byte array containing the data to be sent.
524         * 
525         * @throws InterfaceNotOpenException if this device connection is not open.
526         * @throws NullPointerException if {@code address == null} or 
527         *                              if {@code data == null}.
528         * @throws XBeeException if there is any XBee related exception.
529         * 
530         * @see #sendData(RemoteXBeeDevice, byte[])
531         * @see #sendData(XBee64BitAddress, byte[])
532         * @see #sendData(XBee64BitAddress, XBee16BitAddress, byte[])
533         * @see #sendDataAsync(RemoteXBeeDevice, byte[])
534         * @see #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[])
535         * @see com.digi.xbee.api.models.XBee64BitAddress
536         */
537        protected void sendDataAsync(XBee64BitAddress address, byte[] data) throws XBeeException {
538                // Verify the parameters are not null, if they are null, throw an exception.
539                if (address == null)
540                        throw new NullPointerException("Address cannot be null");
541                if (data == null)
542                        throw new NullPointerException("Data cannot be null");
543                
544                // Check if device is remote.
545                if (isRemote())
546                        throw new OperationNotSupportedException("Cannot send data to a remote device from a remote device.");
547                
548                logger.debug(toString() + "Sending data asynchronously to {} >> {}.", address, HexUtils.prettyHexString(data));
549                
550                XBeePacket xbeePacket;
551                switch (getXBeeProtocol()) {
552                case RAW_802_15_4:
553                        xbeePacket = new TX64Packet(getNextFrameID(), address, XBeeTransmitOptions.NONE, data);
554                        break;
555                default:
556                        xbeePacket = new TransmitPacket(getNextFrameID(), address, XBee16BitAddress.UNKNOWN_ADDRESS, 0, XBeeTransmitOptions.NONE, data);
557                }
558                sendAndCheckXBeePacket(xbeePacket, true);
559        }
560        
561        /**
562         * Sends asynchronously the provided data to the XBee device of the network 
563         * corresponding to the given 64-bit/16-bit address.
564         * 
565         * <p>Asynchronous transmissions do not wait for answer from the remote 
566         * device or for transmit status packet.</p>
567         * 
568         * @param address64Bit The 64-bit address of the XBee that will receive the 
569         *                     data.
570         * @param address16Bit The 16-bit address of the XBee that will receive the 
571         *                     data. If it is unknown the 
572         *                     {@code XBee16BitAddress.UNKNOWN_ADDRESS} must be 
573         *                     used.
574         * @param data Byte array containing the data to be sent.
575         * 
576         * @throws InterfaceNotOpenException if this device connection is not open.
577         * @throws NullPointerException if {@code address64Bit == null} or 
578         *                              if {@code address16Bit == null} or
579         *                              if {@code data == null}.
580         * @throws XBeeException if a remote device is trying to send data or 
581         *                       if there is any other XBee related exception.
582         * 
583         * @see #sendData(RemoteXBeeDevice, byte[])
584         * @see #sendData(XBee64BitAddress, byte[])
585         * @see #sendData(XBee64BitAddress, XBee16BitAddress, byte[])
586         * @see #sendDataAsync(RemoteXBeeDevice, byte[])
587         * @see #sendDataAsync(XBee64BitAddress, byte[])
588         * @see com.digi.xbee.api.models.XBee16BitAddress
589         * @see com.digi.xbee.api.models.XBee64BitAddress
590         */
591        protected void sendDataAsync(XBee64BitAddress address64Bit, XBee16BitAddress address16Bit, byte[] data) throws XBeeException {
592                // Verify the parameters are not null, if they are null, throw an exception.
593                if (address64Bit == null)
594                        throw new NullPointerException("64-bit address cannot be null");
595                if (address16Bit == null)
596                        throw new NullPointerException("16-bit address cannot be null");
597                if (data == null)
598                        throw new NullPointerException("Data cannot be null");
599                
600                // Check if device is remote.
601                if (isRemote())
602                        throw new OperationNotSupportedException("Cannot send data to a remote device from a remote device.");
603                
604                logger.debug(toString() + "Sending data asynchronously to {}[{}] >> {}.", 
605                                address64Bit, address16Bit, HexUtils.prettyHexString(data));
606                
607                XBeePacket xbeePacket = new TransmitPacket(getNextFrameID(), address64Bit, address16Bit, 0, XBeeTransmitOptions.NONE, data);
608                sendAndCheckXBeePacket(xbeePacket, true);
609        }
610        
611        /**
612         * Sends the provided data to the provided XBee device asynchronously 
613         * choosing the optimal send method depending on the protocol of the local 
614         * XBee device.
615         * 
616         * <p>Asynchronous transmissions do not wait for answer from the remote 
617         * device or for transmit status packet.</p>
618         * 
619         * @param remoteXBeeDevice The XBee device of the network that will receive the 
620         *                   data.
621         * @param data Byte array containing the data to be sent.
622         * 
623         * @throws InterfaceNotOpenException if this device connection is not open.
624         * @throws NullPointerException if {@code remoteXBeeDevice == null} or 
625         *                              if {@code data == null}.
626         * @throws XBeeException if there is any XBee related exception.
627         * 
628         * @see #sendData(RemoteXBeeDevice, byte[])
629         * @see #sendData(XBee64BitAddress, byte[])
630         * @see #sendData(XBee64BitAddress, XBee16BitAddress, byte[])
631         * @see #sendDataAsync(XBee64BitAddress, byte[])
632         * @see #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[])
633         * @see RemoteXBeeDevice
634         */
635        public void sendDataAsync(RemoteXBeeDevice remoteXBeeDevice, byte[] data) throws XBeeException {
636                if (remoteXBeeDevice == null)
637                        throw new NullPointerException("Remote XBee device cannot be null");
638                
639                switch (getXBeeProtocol()) {
640                case ZIGBEE:
641                case DIGI_POINT:
642                        if (remoteXBeeDevice.get64BitAddress() != null && remoteXBeeDevice.get16BitAddress() != null)
643                                sendDataAsync(remoteXBeeDevice.get64BitAddress(), remoteXBeeDevice.get16BitAddress(), data);
644                        else
645                                sendDataAsync(remoteXBeeDevice.get64BitAddress(), data);
646                        break;
647                case RAW_802_15_4:
648                        if (this instanceof Raw802Device) {
649                                if (remoteXBeeDevice.get64BitAddress() != null)
650                                        ((Raw802Device)this).sendDataAsync(remoteXBeeDevice.get64BitAddress(), data);
651                                else
652                                        ((Raw802Device)this).sendDataAsync(remoteXBeeDevice.get16BitAddress(), data);
653                        } else
654                                sendDataAsync(remoteXBeeDevice.get64BitAddress(), data);
655                        break;
656                case DIGI_MESH:
657                default:
658                        sendDataAsync(remoteXBeeDevice.get64BitAddress(), data);
659                }
660        }
661        
662        /**
663         * Sends the provided data to the XBee device of the network corresponding 
664         * to the given 64-bit address.
665         * 
666         * <p>This method blocks till a success or error response arrives or the 
667         * configured receive timeout expires.</p>
668         * 
669         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
670         * method and can be consulted with {@code getReceiveTimeout} method.</p>
671         * 
672         * <p>For non-blocking operations use the method 
673         * {@link #sendDataAsync(XBee64BitAddress, byte[])}.</p>
674         * 
675         * @param address The 64-bit address of the XBee that will receive the data.
676         * @param data Byte array containing the data to be sent.
677         * 
678         * @throws InterfaceNotOpenException if this device connection is not open.
679         * @throws NullPointerException if {@code address == null} or 
680         *                              if {@code data == null}.
681         * @throws TimeoutException if there is a timeout sending the data.
682         * @throws XBeeException if there is any other XBee related exception.
683         * 
684         * @see #getReceiveTimeout()
685         * @see #setReceiveTimeout(int)
686         * @see #sendData(RemoteXBeeDevice, byte[])
687         * @see #sendData(XBee64BitAddress, XBee16BitAddress, byte[])
688         * @see #sendDataAsync(RemoteXBeeDevice, byte[])
689         * @see #sendDataAsync(XBee64BitAddress, byte[])
690         * @see #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[])
691         * @see com.digi.xbee.api.models.XBee64BitAddress
692         */
693        protected void sendData(XBee64BitAddress address, byte[] data) throws TimeoutException, XBeeException {
694                // Verify the parameters are not null, if they are null, throw an exception.
695                if (address == null)
696                        throw new NullPointerException("Address cannot be null");
697                if (data == null)
698                        throw new NullPointerException("Data cannot be null");
699                
700                // Check if device is remote.
701                if (isRemote())
702                        throw new OperationNotSupportedException("Cannot send data to a remote device from a remote device.");
703                
704                logger.debug(toString() + "Sending data to {} >> {}.", address, HexUtils.prettyHexString(data));
705                
706                XBeePacket xbeePacket;
707                switch (getXBeeProtocol()) {
708                case RAW_802_15_4:
709                        xbeePacket = new TX64Packet(getNextFrameID(), address, XBeeTransmitOptions.NONE, data);
710                        break;
711                default:
712                        xbeePacket = new TransmitPacket(getNextFrameID(), address, XBee16BitAddress.UNKNOWN_ADDRESS, 0, XBeeTransmitOptions.NONE, data);
713                }
714                sendAndCheckXBeePacket(xbeePacket, false);
715        }
716        
717        /**
718         * Sends the provided data to the XBee device of the network corresponding 
719         * to the given 64-bit/16-bit address.
720         * 
721         * <p>This method blocks till a success or error response arrives or the 
722         * configured receive timeout expires.</p>
723         * 
724         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
725         * method and can be consulted with {@code getReceiveTimeout} method.</p>
726         * 
727         * <p>For non-blocking operations use the method 
728         * {@link #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[])}.</p>
729         * 
730         * @param address64Bit The 64-bit address of the XBee that will receive the 
731         *                     data.
732         * @param address16Bit The 16-bit address of the XBee that will receive the 
733         *                     data. If it is unknown the 
734         *                     {@code XBee16BitAddress.UNKNOWN_ADDRESS} must be 
735         *                     used.
736         * @param data Byte array containing the data to be sent.
737         * 
738         * @throws InterfaceNotOpenException if this device connection is not open.
739         * @throws NullPointerException if {@code address64Bit == null} or 
740         *                              if {@code address16Bit == null} or
741         *                              if {@code data == null}.
742         * @throws TimeoutException if there is a timeout sending the data.
743         * @throws XBeeException if a remote device is trying to send data or 
744         *                       if there is any other XBee related exception.
745         * 
746         * @see #getReceiveTimeout()
747         * @see #setReceiveTimeout(int)
748         * @see #sendData(RemoteXBeeDevice, byte[])
749         * @see #sendData(XBee64BitAddress, byte[])
750         * @see #sendDataAsync(RemoteXBeeDevice, byte[])
751         * @see #sendDataAsync(XBee64BitAddress, byte[])
752         * @see #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[])
753         * @see com.digi.xbee.api.models.XBee16BitAddress
754         * @see com.digi.xbee.api.models.XBee64BitAddress
755         */
756        protected void sendData(XBee64BitAddress address64Bit, XBee16BitAddress address16Bit, byte[] data) throws TimeoutException, XBeeException {
757                // Verify the parameters are not null, if they are null, throw an exception.
758                if (address64Bit == null)
759                        throw new NullPointerException("64-bit address cannot be null");
760                if (address16Bit == null)
761                        throw new NullPointerException("16-bit address cannot be null");
762                if (data == null)
763                        throw new NullPointerException("Data cannot be null");
764                
765                // Check if device is remote.
766                if (isRemote())
767                        throw new OperationNotSupportedException("Cannot send data to a remote device from a remote device.");
768                
769                logger.debug(toString() + "Sending data to {}[{}] >> {}.", 
770                                address64Bit, address16Bit, HexUtils.prettyHexString(data));
771                
772                XBeePacket xbeePacket = new TransmitPacket(getNextFrameID(), address64Bit, address16Bit, 0, XBeeTransmitOptions.NONE, data);
773                sendAndCheckXBeePacket(xbeePacket, false);
774        }
775        
776        /**
777         * Sends the provided data to the given XBee device choosing the optimal 
778         * send method depending on the protocol of the local XBee device.
779         * 
780         * <p>This method blocks till a success or error response arrives or the 
781         * configured receive timeout expires.</p>
782         * 
783         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
784         * method and can be consulted with {@code getReceiveTimeout} method.</p>
785         * 
786         * <p>For non-blocking operations use the method 
787         * {@link #sendDataAsync(RemoteXBeeDevice, byte[])}.</p>
788         * 
789         * @param remoteXBeeDevice The XBee device of the network that will receive 
790         *                         the data.
791         * @param data Byte array containing the data to be sent.
792         * 
793         * @throws InterfaceNotOpenException if this device connection is not open.
794         * @throws NullPointerException if {@code xbeeDevice == null} or 
795         *                              if {@code data == null}.
796         * @throws TimeoutException if there is a timeout sending the data.
797         * @throws XBeeException if there is any other XBee related exception.
798         * 
799         * @see #getReceiveTimeout()
800         * @see #setReceiveTimeout(int)
801         * @see #sendData(XBee64BitAddress, byte[])
802         * @see #sendData(XBee64BitAddress, XBee16BitAddress, byte[])
803         * @see #sendDataAsync(RemoteXBeeDevice, byte[])
804         * @see #sendDataAsync(XBee64BitAddress, byte[])
805         * @see #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[])
806         * @see com.digi.xbee.api.RemoteXBeeDevice
807         */
808        public void sendData(RemoteXBeeDevice remoteXBeeDevice, byte[] data) throws TimeoutException, XBeeException {
809                if (remoteXBeeDevice == null)
810                        throw new NullPointerException("Remote XBee device cannot be null");
811                
812                switch (getXBeeProtocol()) {
813                case ZIGBEE:
814                case DIGI_POINT:
815                        if (remoteXBeeDevice.get64BitAddress() != null && remoteXBeeDevice.get16BitAddress() != null)
816                                sendData(remoteXBeeDevice.get64BitAddress(), remoteXBeeDevice.get16BitAddress(), data);
817                        else
818                                sendData(remoteXBeeDevice.get64BitAddress(), data);
819                        break;
820                case RAW_802_15_4:
821                        if (this instanceof Raw802Device) {
822                                if (remoteXBeeDevice.get64BitAddress() != null)
823                                        ((Raw802Device)this).sendData(remoteXBeeDevice.get64BitAddress(), data);
824                                else
825                                        ((Raw802Device)this).sendData(remoteXBeeDevice.get16BitAddress(), data);
826                        } else
827                                sendData(remoteXBeeDevice.get64BitAddress(), data);
828                        break;
829                case DIGI_MESH:
830                default:
831                        sendData(remoteXBeeDevice.get64BitAddress(), data);
832                }
833        }
834        
835        /**
836         * Sends the provided data to all the XBee nodes of the network (broadcast).
837         * 
838         * <p>This method blocks till a success or error transmit status arrives or 
839         * the configured receive timeout expires.</p>
840         * 
841         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
842         * method and can be consulted with {@code getReceiveTimeout} method.</p>
843         * 
844         * @param data Byte array containing the data to be sent.
845         * 
846         * @throws InterfaceNotOpenException if this device connection is not open.
847         * @throws NullPointerException if {@code data == null}.
848         * @throws TimeoutException if there is a timeout sending the data.
849         * @throws XBeeException if there is any other XBee related exception.
850         * 
851         * @see #getReceiveTimeout()
852         * @see #setReceiveTimeout(int)
853         */
854        public void sendBroadcastData(byte[] data) throws TimeoutException, XBeeException {
855                sendData(XBee64BitAddress.BROADCAST_ADDRESS, data);
856        }
857        
858        /**
859         * Sends asynchronously the provided data in application layer mode to the 
860         * XBee device of the network corresponding to the given 64-bit address. 
861         * Application layer mode means that you need to specify the application 
862         * layer fields to be sent with the data.
863         * 
864         * <p>Asynchronous transmissions do not wait for answer from the remote 
865         * device or for transmit status packet.</p>
866         * 
867         * @param address The 64-bit address of the XBee that will receive the data.
868         * @param sourceEndpoint Source endpoint for the transmission.
869         * @param destEndpoint Destination endpoint for the transmission.
870         * @param clusterID Cluster ID used in the transmission.
871         * @param profileID Profile ID used in the transmission.
872         * @param data Byte array containing the data to be sent.
873         * 
874         * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 
875         *                                  if {@code sourceEndpoint > 0xFF} or 
876         *                                  if {@code destEndpoint < 0} or 
877         *                                  if {@code destEndpoint > 0xFF} or 
878         *                                  if {@code clusterID < 0} or 
879         *                                  if {@code clusterID > 0xFFFF} or 
880         *                                  if {@code profileID < 0} or 
881         *                                  if {@code profileID > 0xFFFF}.
882         * @throws InterfaceNotOpenException if this device connection is not open.
883         * @throws NullPointerException if {@code address == null} or 
884         *                              if {@code data == null}.
885         * @throws XBeeException if there is any other XBee related exception.
886         * 
887         * @see #sendExplicitData(RemoteXBeeDevice, int, int, int, int, byte[])
888         * @see #sendExplicitData(XBee64BitAddress, int, int, int, int, byte[])
889         * @see #sendExplicitData(XBee64BitAddress, XBee16BitAddress, int, int, int, int, byte[])
890         * @see #sendExplicitDataAsync(RemoteXBeeDevice, int, int, int, int, byte[])
891         * @see #sendExplicitDataAsync(XBee64BitAddress, XBee16BitAddress, int, int, int, int, byte[])
892         * @see com.digi.xbee.api.models.XBee64BitAddress
893         */
894        protected void sendExplicitDataAsync(XBee64BitAddress address, int sourceEndpoint, int destEndpoint, int clusterID, 
895                        int profileID, byte[] data) throws XBeeException {
896                if (address == null)
897                        throw new NullPointerException("Address cannot be null");
898                if (data == null)
899                        throw new NullPointerException("Data cannot be null.");
900                if (sourceEndpoint < 0 || sourceEndpoint > 0xFF)
901                        throw new IllegalArgumentException("Source endpoint must be between 0 and 0xFF.");
902                if (destEndpoint < 0 || destEndpoint > 0xFF)
903                        throw new IllegalArgumentException("Destination endpoint must be between 0 and 0xFF.");
904                if (clusterID < 0 || clusterID > 0xFFFF)
905                        throw new IllegalArgumentException("Cluster ID must be between 0 and 0xFFFF.");
906                if (profileID < 0 || profileID > 0xFFFF)
907                        throw new IllegalArgumentException("Profile ID must be between 0 and 0xFFFF.");
908                
909                // Check if device is remote.
910                if (isRemote())
911                        throw new OperationNotSupportedException("Cannot send explicit data to a remote device from a remote device.");
912                
913                logger.debug(toString() + "Sending explicit data asynchronously to {} [{} - {} - {} - {}] >> {}.", address, HexUtils.integerToHexString(sourceEndpoint, 1), 
914                                HexUtils.integerToHexString(destEndpoint, 1), HexUtils.integerToHexString(clusterID, 2), 
915                                HexUtils.integerToHexString(profileID, 2), HexUtils.prettyHexString(data));
916                
917                XBeePacket xbeePacket = new ExplicitAddressingPacket(getNextFrameID(), address, XBee16BitAddress.UNKNOWN_ADDRESS, sourceEndpoint, destEndpoint, clusterID, profileID, 0, XBeeTransmitOptions.NONE, data);
918                sendAndCheckXBeePacket(xbeePacket, true);
919        }
920        
921        /**
922         * Sends asynchronously the provided data in application layer mode to the 
923         * XBee device of the network corresponding to the given 64-bit/16-bit 
924         * address. Application layer mode means that you need to specify the 
925         * application layer fields to be sent with the data.
926         * 
927         * <p>Asynchronous transmissions do not wait for answer from the remote 
928         * device or for transmit status packet.</p>
929         * 
930         * @param address64Bit The 64-bit address of the XBee that will receive the 
931         *                     data.
932         * @param address16Bit The 16-bit address of the XBee that will receive the 
933         *                     data. If it is unknown the 
934         *                     {@code XBee16BitAddress.UNKNOWN_ADDRESS} must be 
935         *                     used.
936         * @param sourceEndpoint Source endpoint for the transmission.
937         * @param destEndpoint Destination endpoint for the transmission.
938         * @param clusterID Cluster ID used in the transmission.
939         * @param profileID Profile ID used in the transmission.
940         * @param data Byte array containing the data to be sent.
941         * 
942         * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 
943         *                                  if {@code sourceEndpoint > 0xFF} or 
944         *                                  if {@code destEndpoint < 0} or 
945         *                                  if {@code destEndpoint > 0xFF} or 
946         *                                  if {@code clusterID < 0} or 
947         *                                  if {@code clusterID > 0xFFFF} or 
948         *                                  if {@code profileID < 0} or 
949         *                                  if {@code profileID > 0xFFFF}.
950         * @throws InterfaceNotOpenException if this device connection is not open.
951         * @throws NullPointerException if {@code address64Bit == null} or 
952         *                              if {@code address16Bit == null} or 
953         *                              if {@code data == null}.
954         * @throws XBeeException if there is any other XBee related exception.
955         * 
956         * @see #sendExplicitData(RemoteXBeeDevice, int, int, int, int, byte[])
957         * @see #sendExplicitData(XBee64BitAddress, int, int, int, int, byte[])
958         * @see #sendExplicitData(XBee64BitAddress, XBee16BitAddress, int, int, int, int, byte[])
959         * @see #sendExplicitDataAsync(RemoteXBeeDevice, int, int, int, int, byte[])
960         * @see #sendExplicitDataAsync(XBee64BitAddress, int, int, int, int, byte[])
961         * @see com.digi.xbee.api.models.XBee16BitAddress
962         * @see com.digi.xbee.api.models.XBee64BitAddress
963         */
964        protected void sendExplicitDataAsync(XBee64BitAddress address64Bit, XBee16BitAddress address16Bit, int sourceEndpoint, 
965                        int destEndpoint, int clusterID, int profileID, byte[] data) throws XBeeException {
966                if (address64Bit == null)
967                        throw new NullPointerException("64-bit address cannot be null.");
968                if (address16Bit == null)
969                        throw new NullPointerException("16-bit address cannot be null.");
970                if (data == null)
971                        throw new NullPointerException("Data cannot be null.");
972                if (sourceEndpoint < 0 || sourceEndpoint > 0xFF)
973                        throw new IllegalArgumentException("Source endpoint must be between 0 and 0xFF.");
974                if (destEndpoint < 0 || destEndpoint > 0xFF)
975                        throw new IllegalArgumentException("Destination endpoint must be between 0 and 0xFF.");
976                if (clusterID < 0 || clusterID > 0xFFFF)
977                        throw new IllegalArgumentException("Cluster ID must be between 0 and 0xFFFF.");
978                if (profileID < 0 || profileID > 0xFFFF)
979                        throw new IllegalArgumentException("Profile ID must be between 0 and 0xFFFF.");
980                
981                // Check if device is remote.
982                if (isRemote())
983                        throw new OperationNotSupportedException("Cannot send explicit data to a remote device from a remote device.");
984                
985                logger.debug(toString() + "Sending explicit data asynchronously to {}[{}] [{} - {} - {} - {}] >> {}.", address64Bit, address16Bit, 
986                                HexUtils.integerToHexString(sourceEndpoint, 1), HexUtils.integerToHexString(destEndpoint, 1), 
987                                HexUtils.integerToHexString(clusterID, 2), HexUtils.integerToHexString(profileID, 2), 
988                                HexUtils.prettyHexString(data));
989                
990                XBeePacket xbeePacket = new ExplicitAddressingPacket(getNextFrameID(), address64Bit, address16Bit, sourceEndpoint, destEndpoint, clusterID, profileID, 0, XBeeTransmitOptions.NONE, data);
991                sendAndCheckXBeePacket(xbeePacket, true);
992        }
993        
994        /**
995         * Sends asynchronously the provided data in application layer mode to the 
996         * provided XBee device choosing the optimal send method depending on the 
997         * protocol of the local XBee device. Application layer mode means that you 
998         * need to specify the application layer fields to be sent with the data.
999         * 
1000         * <p>Asynchronous transmissions do not wait for answer from the remote 
1001         * device or for transmit status packet.</p>
1002         * 
1003         * @param remoteXBeeDevice The XBee device of the network that will receive 
1004         *                         the data.
1005         * @param sourceEndpoint Source endpoint for the transmission.
1006         * @param destEndpoint Destination endpoint for the transmission.
1007         * @param clusterID Cluster ID used in the transmission.
1008         * @param profileID Profile ID used in the transmission.
1009         * @param data Byte array containing the data to be sent.
1010         * 
1011         * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 
1012         *                                  if {@code sourceEndpoint > 0xFF} or 
1013         *                                  if {@code destEndpoint < 0} or 
1014         *                                  if {@code destEndpoint > 0xFF} or 
1015         *                                  if {@code clusterID < 0} or 
1016         *                                  if {@code clusterID > 0xFFFF} or 
1017         *                                  if {@code profileID < 0} or 
1018         *                                  if {@code profileID > 0xFFFF}.
1019         * @throws InterfaceNotOpenException if this device connection is not open.
1020         * @throws NullPointerException if {@code remoteXBeeDevice == null} or 
1021         *                              if {@code data == null}.
1022         * @throws XBeeException if there is any other XBee related exception.
1023         * 
1024         * @see #sendExplicitData(RemoteXBeeDevice, int, int, int, int, byte[])
1025         * @see #sendExplicitData(XBee64BitAddress, int, int, int, int, byte[])
1026         * @see #sendExplicitData(XBee64BitAddress, XBee16BitAddress, int, int, int, int, byte[])
1027         * @see #sendExplicitDataAsync(XBee64BitAddress, int, int, int, int, byte[])
1028         * @see #sendExplicitDataAsync(XBee64BitAddress, XBee16BitAddress, int, int, int, int, byte[])
1029         * @see RemoteXBeeDevice
1030         */
1031        protected void sendExplicitDataAsync(RemoteXBeeDevice remoteXBeeDevice, int sourceEndpoint, int destEndpoint, 
1032                        int clusterID, int profileID, byte[] data) throws XBeeException {
1033                if (remoteXBeeDevice == null)
1034                        throw new NullPointerException("Remote XBee device cannot be null");
1035                
1036                switch (getXBeeProtocol()) {
1037                case ZIGBEE:
1038                case DIGI_POINT:
1039                        if (remoteXBeeDevice.get64BitAddress() != null && remoteXBeeDevice.get16BitAddress() != null)
1040                                sendExplicitDataAsync(remoteXBeeDevice.get64BitAddress(), remoteXBeeDevice.get16BitAddress(), sourceEndpoint, destEndpoint, clusterID, profileID, data);
1041                        else
1042                                sendExplicitDataAsync(remoteXBeeDevice.get64BitAddress(), sourceEndpoint, destEndpoint, clusterID, profileID, data);
1043                        break;
1044                case RAW_802_15_4:
1045                        throw new OperationNotSupportedException("802.15.4. protocol does not support explicit data transmissions.");
1046                case DIGI_MESH:
1047                default:
1048                        sendExplicitDataAsync(remoteXBeeDevice.get64BitAddress(), sourceEndpoint, destEndpoint, clusterID, profileID, data);
1049                }
1050        }
1051        
1052        /**
1053         * Sends the provided data in application layer mode to the XBee device of 
1054         * the network corresponding to the given 64-bit address. Application layer 
1055         * mode means that you need to specify the application layer fields to be 
1056         * sent with the data.
1057         * 
1058         * <p>This method blocks till a success or error response arrives or the 
1059         * configured receive timeout expires.</p>
1060         * 
1061         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
1062         * method and can be consulted with {@code getReceiveTimeout} method.</p>
1063         * 
1064         * @param address The 64-bit address of the XBee that will receive the data.
1065         * @param sourceEndpoint Source endpoint for the transmission.
1066         * @param destEndpoint Destination endpoint for the transmission.
1067         * @param clusterID Cluster ID used in the transmission.
1068         * @param profileID Profile ID used in the transmission.
1069         * @param data Byte array containing the data to be sent.
1070         * 
1071         * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 
1072         *                                  if {@code sourceEndpoint > 0xFF} or 
1073         *                                  if {@code destEndpoint < 0} or 
1074         *                                  if {@code destEndpoint > 0xFF} or 
1075         *                                  if {@code clusterID < 0} or 
1076         *                                  if {@code clusterID > 0xFFFF} or 
1077         *                                  if {@code profileID < 0} or 
1078         *                                  if {@code profileID > 0xFFFF}.
1079         * @throws InterfaceNotOpenException if this device connection is not open.
1080         * @throws NullPointerException if {@code address == null} or 
1081         *                              if {@code data == null}.
1082         * @throws TimeoutException if there is a timeout sending the data.
1083         * @throws XBeeException if there is any other XBee related exception.
1084         * 
1085         * @see #getReceiveTimeout()
1086         * @see #sendExplicitData(RemoteXBeeDevice, int, int, int, int, byte[])
1087         * @see #sendExplicitData(XBee64BitAddress, XBee16BitAddress, int, int, int, int, byte[])
1088         * @see #setReceiveTimeout(int)
1089         * @see com.digi.xbee.api.models.XBee64BitAddress
1090         */
1091        protected void sendExplicitData(XBee64BitAddress address, int sourceEndpoint, int destEndpoint, int clusterID, 
1092                        int profileID, byte[] data) throws TimeoutException, XBeeException {
1093                if (address == null)
1094                        throw new NullPointerException("Address cannot be null");
1095                if (data == null)
1096                        throw new NullPointerException("Data cannot be null.");
1097                if (sourceEndpoint < 0 || sourceEndpoint > 0xFF)
1098                        throw new IllegalArgumentException("Source endpoint must be between 0 and 0xFF.");
1099                if (destEndpoint < 0 || destEndpoint > 0xFF)
1100                        throw new IllegalArgumentException("Destination endpoint must be between 0 and 0xFF.");
1101                if (clusterID < 0 || clusterID > 0xFFFF)
1102                        throw new IllegalArgumentException("Cluster ID must be between 0 and 0xFFFF.");
1103                if (profileID < 0 || profileID > 0xFFFF)
1104                        throw new IllegalArgumentException("Profile ID must be between 0 and 0xFFFF.");
1105                
1106                // Check if device is remote.
1107                if (isRemote())
1108                        throw new OperationNotSupportedException("Cannot send explicit data to a remote device from a remote device.");
1109                
1110                logger.debug(toString() + "Sending explicit data to {} [{} - {} - {} - {}] >> {}.", address, HexUtils.integerToHexString(sourceEndpoint, 1), 
1111                                HexUtils.integerToHexString(destEndpoint, 1), HexUtils.integerToHexString(clusterID, 2), 
1112                                HexUtils.integerToHexString(profileID, 2), HexUtils.prettyHexString(data));
1113                
1114                XBeePacket xbeePacket = new ExplicitAddressingPacket(getNextFrameID(), address, XBee16BitAddress.UNKNOWN_ADDRESS, sourceEndpoint, destEndpoint, clusterID, profileID, 0, XBeeTransmitOptions.NONE, data);
1115                sendAndCheckXBeePacket(xbeePacket, false);
1116        }
1117        
1118        /**
1119         * Sends the provided data in application layer mode to the XBee device of 
1120         * the network corresponding to the given 64-bit/16-bit address. 
1121         * Application layer mode means that you need to specify the application 
1122         * layer fields to be sent with the data.
1123         * 
1124         * <p>This method blocks till a success or error response arrives or the 
1125         * configured receive timeout expires.</p>
1126         * 
1127         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
1128         * method and can be consulted with {@code getReceiveTimeout} method.</p>
1129         * 
1130         * @param address64Bit The 64-bit address of the XBee that will receive the 
1131         *                     data.
1132         * @param address16Bit The 16-bit address of the XBee that will receive the 
1133         *                     data. If it is unknown the 
1134         *                     {@code XBee16BitAddress.UNKNOWN_ADDRESS} must be 
1135         *                     used.
1136         * @param sourceEndpoint Source endpoint for the transmission.
1137         * @param destEndpoint Destination endpoint for the transmission.
1138         * @param clusterID Cluster ID used in the transmission.
1139         * @param profileID Profile ID used in the transmission.
1140         * @param data Byte array containing the data to be sent.
1141         * 
1142         * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 
1143         *                                  if {@code sourceEndpoint > 0xFF} or 
1144         *                                  if {@code destEndpoint < 0} or 
1145         *                                  if {@code destEndpoint > 0xFF} or 
1146         *                                  if {@code clusterID < 0} or 
1147         *                                  if {@code clusterID > 0xFFFF} or 
1148         *                                  if {@code profileID < 0} or 
1149         *                                  if {@code profileID > 0xFFFF}.
1150         * @throws InterfaceNotOpenException if this device connection is not open.
1151         * @throws NullPointerException if {@code address == null} or 
1152         *                              if {@code data == null}.
1153         * @throws TimeoutException if there is a timeout sending the data.
1154         * @throws XBeeException if there is any other XBee related exception.
1155         * 
1156         * @see #getReceiveTimeout()
1157         * @see #sendExplicitData(RemoteXBeeDevice, int, int, int, int, byte[])
1158         * @see #sendExplicitData(XBee64BitAddress, int, int, int, int, byte[])
1159         * @see #setReceiveTimeout(int)
1160         * @see com.digi.xbee.api.models.XBee16BitAddress
1161         * @see com.digi.xbee.api.models.XBee64BitAddress
1162         */
1163        protected void sendExplicitData(XBee64BitAddress address64Bit, XBee16BitAddress address16Bit, int sourceEndpoint, int destEndpoint, 
1164                        int clusterID, int profileID, byte[] data) throws TimeoutException, XBeeException {
1165                // Verify the parameters are not null, if they are null, throw an exception.
1166                if (address64Bit == null)
1167                        throw new NullPointerException("64-bit address cannot be null");
1168                if (address16Bit == null)
1169                        throw new NullPointerException("16-bit address cannot be null");
1170                if (data == null)
1171                        throw new NullPointerException("Data cannot be null.");
1172                if (sourceEndpoint < 0 || sourceEndpoint > 0xFF)
1173                        throw new IllegalArgumentException("Source endpoint must be between 0 and 0xFF.");
1174                if (destEndpoint < 0 || destEndpoint > 0xFF)
1175                        throw new IllegalArgumentException("Destination endpoint must be between 0 and 0xFF.");
1176                if (clusterID < 0 || clusterID > 0xFFFF)
1177                        throw new IllegalArgumentException("Cluster ID must be between 0 and 0xFFFF.");
1178                if (profileID < 0 || profileID > 0xFFFF)
1179                        throw new IllegalArgumentException("Profile ID must be between 0 and 0xFFFF.");
1180                
1181                // Check if device is remote.
1182                if (isRemote())
1183                        throw new OperationNotSupportedException("Cannot send explicit data to a remote device from a remote device.");
1184                
1185                logger.debug(toString() + "Sending explicit data to {}[{}] [{} - {} - {} - {}] >> {}.", address64Bit, address16Bit, 
1186                                HexUtils.integerToHexString(sourceEndpoint, 1), HexUtils.integerToHexString(destEndpoint, 1), 
1187                                HexUtils.integerToHexString(clusterID, 2), HexUtils.integerToHexString(profileID, 2), 
1188                                HexUtils.prettyHexString(data));
1189                
1190                XBeePacket xbeePacket = new ExplicitAddressingPacket(getNextFrameID(), address64Bit, address16Bit, sourceEndpoint, destEndpoint, clusterID, profileID, 0, XBeeTransmitOptions.NONE, data);
1191                sendAndCheckXBeePacket(xbeePacket, false);
1192        }
1193        
1194        /**
1195         * Sends the provided data to the given XBee device in application layer 
1196         * mode choosing the optimal send method depending on the protocol of the 
1197         * local XBee device. Application layer mode means that you need to specify 
1198         * the application layer fields to be sent with the data.
1199         * 
1200         * <p>This method blocks till a success or error response arrives or the 
1201         * configured receive timeout expires.</p>
1202         * 
1203         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
1204         * method and can be consulted with {@code getReceiveTimeout} method.</p>
1205         * 
1206         * @param remoteXBeeDevice The XBee device of the network that will receive 
1207         *                         the explicit data.
1208         * @param sourceEndpoint Source endpoint for the transmission.
1209         * @param destEndpoint Destination endpoint for the transmission.
1210         * @param clusterID Cluster ID used in the transmission.
1211         * @param profileID Profile ID used in the transmission.
1212         * @param data Byte array containing the data to be sent.
1213         * 
1214         * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 
1215         *                                  if {@code sourceEndpoint > 0xFF} or 
1216         *                                  if {@code destEndpoint < 0} or 
1217         *                                  if {@code destEndpoint > 0xFF} or 
1218         *                                  if {@code clusterID < 0} or 
1219         *                                  if {@code clusterID > 0xFFFF} or 
1220         *                                  if {@code profileID < 0} or 
1221         *                                  if {@code profileID > 0xFFFF}.
1222         * @throws InterfaceNotOpenException if this device connection is not open.
1223         * @throws NullPointerException if {@code remoteXBeeDevice == null} or
1224         *                              if {@code data == null}.
1225         * @throws TimeoutException if there is a timeout sending the data.
1226         * @throws XBeeException if there is any other XBee related exception.
1227         * 
1228         * @see #getReceiveTimeout()
1229         * @see #sendExplicitData(XBee64BitAddress, int, int, int, int, byte[])
1230         * @see #sendExplicitData(XBee64BitAddress, XBee16BitAddress, int, int, int, int, byte[])
1231         * @see #setReceiveTimeout(int)
1232         * @see com.digi.xbee.api.RemoteXBeeDevice
1233         */
1234        protected void sendExplicitData(RemoteXBeeDevice remoteXBeeDevice, int sourceEndpoint, int destEndpoint, int clusterID, 
1235                        int profileID, byte[] data) throws TimeoutException, XBeeException {
1236                if (remoteXBeeDevice == null)
1237                        throw new NullPointerException("Remote XBee device cannot be null.");
1238                
1239                switch (getXBeeProtocol()) {
1240                case ZIGBEE:
1241                case DIGI_POINT:
1242                        if (remoteXBeeDevice.get64BitAddress() != null && remoteXBeeDevice.get16BitAddress() != null)
1243                                sendExplicitData(remoteXBeeDevice.get64BitAddress(), remoteXBeeDevice.get16BitAddress(), sourceEndpoint, destEndpoint, clusterID, profileID, data);
1244                        else
1245                                sendExplicitData(remoteXBeeDevice.get64BitAddress(), sourceEndpoint, destEndpoint, clusterID, profileID, data);
1246                        break;
1247                case RAW_802_15_4:
1248                        throw new OperationNotSupportedException("802.15.4. protocol does not support explicit data transmissions.");
1249                case DIGI_MESH:
1250                default:
1251                        sendExplicitData(remoteXBeeDevice.get64BitAddress(), sourceEndpoint, destEndpoint, clusterID, profileID, data);
1252                }
1253        }
1254        
1255        /**
1256         * Sends the provided data to all the XBee nodes of the network (broadcast) 
1257         * in application layer mode. Application layer mode means that you need to 
1258         * specify the application layer fields to be sent with the data.
1259         * 
1260         * <p>This method blocks till a success or error transmit status arrives or 
1261         * the configured receive timeout expires.</p>
1262         * 
1263         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
1264         * method and can be consulted with {@code getReceiveTimeout} method.</p>
1265         * 
1266         * @param sourceEndpoint Source endpoint for the transmission.
1267         * @param destEndpoint Destination endpoint for the transmission.
1268         * @param clusterID Cluster ID used in the transmission.
1269         * @param profileID Profile ID used in the transmission.
1270         * @param data Byte array containing the data to be sent.
1271         * 
1272         * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 
1273         *                                  if {@code sourceEndpoint > 0xFF} or 
1274         *                                  if {@code destEndpoint < 0} or 
1275         *                                  if {@code destEndpoint > 0xFF} or 
1276         *                                  if {@code clusterID < 0} or 
1277         *                                  if {@code clusterID > 0xFFFF} or 
1278         *                                  if {@code profileID < 0} or 
1279         *                                  if {@code profileID > 0xFFFF}.
1280         * @throws InterfaceNotOpenException if this device connection is not open.
1281         * @throws NullPointerException if {@code remoteXBeeDevice == null} or
1282         *                              if {@code data == null}.
1283         * @throws TimeoutException if there is a timeout sending the data.
1284         * @throws XBeeException if there is any other XBee related exception.
1285         * 
1286         * @see #getReceiveTimeout()
1287         * @see #setReceiveTimeout(int)
1288         */
1289        protected void sendBroadcastExplicitData(int sourceEndpoint, int destEndpoint, int clusterID, int profileID, 
1290                        byte[] data) throws TimeoutException, XBeeException {
1291                if (getXBeeProtocol() == XBeeProtocol.RAW_802_15_4)
1292                        throw new OperationNotSupportedException("802.15.4. protocol does not support explicit data transmissions.");
1293                sendExplicitData(XBee64BitAddress.BROADCAST_ADDRESS, sourceEndpoint, destEndpoint, clusterID, profileID, data);
1294        }
1295        
1296        /**
1297         * Sends the given XBee packet and registers the given packet listener 
1298         * (if not {@code null}) to be notified when the answers is received.
1299         * 
1300         * <p>This is a non-blocking operation. To wait for the answer use 
1301         * {@code sendPacket(XBeePacket)}.</p>
1302         * 
1303         * @param packet XBee packet to be sent.
1304         * @param packetReceiveListener Listener for the operation, {@code null} 
1305         *                              not to be notified when the answer arrives.
1306         * 
1307         * @throws InterfaceNotOpenException if this device connection is not open.
1308         * @throws NullPointerException if {@code packet == null}.
1309         * @throws XBeeException if there is any other XBee related exception.
1310         * 
1311         * @see #sendPacket(XBeePacket)
1312         * @see #sendPacketAsync(XBeePacket)
1313         * @see com.digi.xbee.api.listeners.IPacketReceiveListener
1314         * @see com.digi.xbee.api.packet.XBeePacket
1315         */
1316        public void sendPacket(XBeePacket packet, IPacketReceiveListener packetReceiveListener) throws XBeeException {
1317                try {
1318                        sendXBeePacket(packet, packetReceiveListener);
1319                } catch (IOException e) {
1320                        throw new XBeeException("Error writing in the communication interface.", e);
1321                }
1322        }
1323        
1324        /**
1325         * Sends the given XBee packet asynchronously.
1326         * 
1327         * <p>This is a non-blocking operation that do not wait for the answer and 
1328         * is never notified when it arrives.</p>
1329         * 
1330         * <p>To be notified when the answer is received, use 
1331         * {@link #sendXBeePacket(XBeePacket, IPacketReceiveListener)}.</p>
1332         * 
1333         * @param packet XBee packet to be sent asynchronously.
1334         * 
1335         * @throws InterfaceNotOpenException if this device connection is not open.
1336         * @throws NullPointerException if {@code packet == null}.
1337         * @throws XBeeException if there is any other XBee related exception.
1338         * 
1339         * @see #sendXBeePacket(XBeePacket)
1340         * @see #sendXBeePacket(XBeePacket, IPacketReceiveListener)
1341         * @see com.digi.xbee.api.packet.XBeePacket
1342         */
1343        public void sendPacketAsync(XBeePacket packet) throws XBeeException {
1344                try {
1345                        super.sendXBeePacket(packet, null);
1346                } catch (IOException e) {
1347                        throw new XBeeException("Error writing in the communication interface.", e);
1348                }
1349        }
1350        
1351        /**
1352         * Sends the given XBee packet synchronously and blocks until the response 
1353         * is received or the configured receive timeout expires.
1354         * 
1355         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
1356         * method and can be consulted with {@code getReceiveTimeout} method.</p>
1357         * 
1358         * <p>Use {@code sendXBeePacketAsync(XBeePacket)} or 
1359         * {@code #sendXBeePacket(XBeePacket, IPacketReceiveListener)} for 
1360         * non-blocking operations.</p>
1361         * 
1362         * @param packet XBee packet to be sent.
1363         * 
1364         * @return An {@code XBeePacket} object containing the response of the sent
1365         *         packet or {@code null} if there is no response.
1366         * 
1367         * @throws InterfaceNotOpenException if this device connection is not open.
1368         * @throws NullPointerException if {@code packet == null}.
1369         * @throws TimeoutException if there is a timeout sending the XBee packet.
1370         * @throws XBeeException if there is any other XBee related exception.
1371         * 
1372         * @see #getReceiveTimeout()
1373         * @see #sendXBeePacket(XBeePacket, IPacketReceiveListener)
1374         * @see #sendXBeePacketAsync(XBeePacket)
1375         * @see #setReceiveTimeout(int)
1376         * @see com.digi.xbee.api.packet.XBeePacket
1377         */
1378        public XBeePacket sendPacket(XBeePacket packet) throws TimeoutException, XBeeException {
1379                try {
1380                        return super.sendXBeePacket(packet);
1381                } catch (IOException e) {
1382                        throw new XBeeException("Error writing in the communication interface.", e);
1383                }
1384        }
1385        
1386        /**
1387         * Waits until a Modem Status packet with a reset status, 
1388         * {@code ModemStatusEvent.STATUS_HARDWARE_RESET} (0x00), or a watchdog 
1389         * timer reset, {@code ModemStatusEvent.STATUS_WATCHDOG_TIMER_RESET} (0x01),
1390         * is received or the timeout expires.
1391         * 
1392         * @return {@code true} if the Modem Status packet is received, 
1393         *                      {@code false} otherwise.
1394         * 
1395         * @see com.digi.xbee.api.models.ModemStatusEvent#STATUS_HARDWARE_RESET
1396         * @see com.digi.xbee.api.models.ModemStatusEvent#STATUS_WATCHDOG_TIMER_RESET
1397         */
1398        private boolean waitForModemResetStatusPacket() {
1399                modemStatusReceived = false;
1400                addModemStatusListener(resetStatusListener);
1401                synchronized (resetLock) {
1402                        try {
1403                                resetLock.wait(TIMEOUT_RESET);
1404                        } catch (InterruptedException e) { }
1405                }
1406                removeModemStatusListener(resetStatusListener);
1407                return modemStatusReceived;
1408        }
1409        
1410        /**
1411         * Custom listener for modem reset packets.
1412         * 
1413         * <p>When a Modem Status packet is received with status 
1414         * {@code ModemStatusEvent.STATUS_HARDWARE_RESET} or 
1415         * {@code ModemStatusEvent.STATUS_WATCHDOG_TIMER_RESET}, it 
1416         * notifies the object that was waiting for the reception.</p>
1417         * 
1418         * @see com.digi.xbee.api.listeners.IModemStatusReceiveListener
1419         * @see com.digi.xbee.api.models.ModemStatusEvent#STATUS_HARDWARE_RESET
1420         * @see com.digi.xbee.api.models.ModemStatusEvent#STATUS_WATCHDOG_TIMER_RESET
1421         */
1422        private IModemStatusReceiveListener resetStatusListener = new IModemStatusReceiveListener() {
1423                
1424                /*
1425                 * (non-Javadoc)
1426                 * @see com.digi.xbee.api.listeners.IModemStatusReceiveListener#modemStatusEventReceived(com.digi.xbee.api.models.ModemStatusEvent)
1427                 */
1428                @Override
1429                public void modemStatusEventReceived(ModemStatusEvent modemStatusEvent) {
1430                        if (modemStatusEvent == ModemStatusEvent.STATUS_HARDWARE_RESET
1431                                        || modemStatusEvent == ModemStatusEvent.STATUS_WATCHDOG_TIMER_RESET){
1432                                modemStatusReceived = true;
1433                                // Continue execution by notifying the lock object.
1434                                synchronized (resetLock) {
1435                                        resetLock.notify();
1436                                }
1437                        }
1438                }
1439        };
1440        
1441        /*
1442         * (non-Javadoc)
1443         * @see com.digi.xbee.api.AbstractXBeeDevice#reset()
1444         */
1445        @Override
1446        public void reset() throws TimeoutException, XBeeException {
1447                // Check connection.
1448                if (!connectionInterface.isOpen())
1449                        throw new InterfaceNotOpenException();
1450                
1451                logger.info(toString() + "Resetting the local module...");
1452                
1453                ATCommandResponse response = null;
1454                try {
1455                        response = sendATCommand(new ATCommand("FR"));
1456                } catch (IOException e) {
1457                        throw new XBeeException("Error writing in the communication interface.", e);
1458                }
1459                
1460                // Check if AT Command response is valid.
1461                checkATCommandResponseIsValid(response);
1462                
1463                // Wait for a Modem Status packet.
1464                if (!waitForModemResetStatusPacket())
1465                        throw new TimeoutException("Timeout waiting for the Modem Status packet.");
1466                
1467                logger.info(toString() + "Module reset successfully.");
1468        }
1469        
1470        /**
1471         * Reads new data received by this XBee device during the configured 
1472         * receive timeout.
1473         * 
1474         * <p>This method blocks until new data is received or the configured 
1475         * receive timeout expires.</p>
1476         * 
1477         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
1478         * method and can be consulted with {@code getReceiveTimeout} method.</p>
1479         * 
1480         * <p>For non-blocking operations, register a {@code IDataReceiveListener} 
1481         * using the method {@link #addDataListener(IDataReceiveListener)}.</p>
1482         * 
1483         * @return An {@code XBeeMessage} object containing the data and the source 
1484         *         address of the remote node that sent the data. {@code null} if 
1485         *         this did not receive new data during the configured receive 
1486         *         timeout.
1487         * 
1488         * @throws InterfaceNotOpenException if this device connection is not open.
1489         * 
1490         * @see #readData(int)
1491         * @see #getReceiveTimeout()
1492         * @see #setReceiveTimeout(int)
1493         * @see #readDataFrom(RemoteXBeeDevice)
1494         * @see #readDataFrom(RemoteXBeeDevice, int)
1495         * @see com.digi.xbee.api.models.XBeeMessage
1496         */
1497        public XBeeMessage readData() {
1498                return readDataPacket(null, TIMEOUT_READ_PACKET);
1499        }
1500        
1501        /**
1502         * Reads new data received by this XBee device during the provided timeout.
1503         * 
1504         * <p>This method blocks until new data is received or the provided timeout 
1505         * expires.</p>
1506         * 
1507         * <p>For non-blocking operations, register a {@code IDataReceiveListener} 
1508         * using the method {@link #addDataListener(IDataReceiveListener)}.</p>
1509         * 
1510         * @param timeout The time to wait for new data in milliseconds.
1511         * 
1512         * @return An {@code XBeeMessage} object containing the data and the source 
1513         *         address of the remote node that sent the data. {@code null} if 
1514         *         this device did not receive new data during {@code timeout} 
1515         *         milliseconds.
1516         * 
1517         * @throws IllegalArgumentException if {@code timeout < 0}.
1518         * @throws InterfaceNotOpenException if this device connection is not open.
1519         * 
1520         * @see #readData()
1521         * @see #readDataFrom(RemoteXBeeDevice)
1522         * @see #readDataFrom(RemoteXBeeDevice, int)
1523         * @see com.digi.xbee.api.models.XBeeMessage
1524         */
1525        public XBeeMessage readData(int timeout) {
1526                if (timeout < 0)
1527                        throw new IllegalArgumentException("Read timeout must be 0 or greater.");
1528                
1529                return readDataPacket(null, timeout);
1530        }
1531        
1532        /**
1533         * Reads new data received from the given remote XBee device during the 
1534         * configured receive timeout.
1535         * 
1536         * <p>This method blocks until new data from the provided remote XBee 
1537         * device is received or the configured receive timeout expires.</p>
1538         * 
1539         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
1540         * method and can be consulted with {@code getReceiveTimeout} method.</p>
1541         * 
1542         * <p>For non-blocking operations, register a {@code IDataReceiveListener} 
1543         * using the method {@link #addDataListener(IDataReceiveListener)}.</p>
1544         * 
1545         * @param remoteXBeeDevice The remote device to read data from.
1546         * 
1547         * @return An {@code XBeeMessage} object containing the data and the source
1548         *         address of the remote node that sent the data. {@code null} if 
1549         *         this device did not receive new data from the provided remote 
1550         *         XBee device during the configured receive timeout.
1551         * 
1552         * @throws InterfaceNotOpenException if this device connection is not open.
1553         * @throws NullPointerException if {@code remoteXBeeDevice == null}.
1554         * 
1555         * @see #readDataFrom(RemoteXBeeDevice, int)
1556         * @see #getReceiveTimeout()
1557         * @see #setReceiveTimeout(int)
1558         * @see #readData()
1559         * @see #readData(int)
1560         * @see RemoteXBeeDevice
1561         * @see com.digi.xbee.api.models.XBeeMessage
1562         */
1563        public XBeeMessage readDataFrom(RemoteXBeeDevice remoteXBeeDevice) {
1564                if (remoteXBeeDevice == null)
1565                        throw new NullPointerException("Remote XBee device cannot be null.");
1566                
1567                return readDataPacket(remoteXBeeDevice, TIMEOUT_READ_PACKET);
1568        }
1569        
1570        /**
1571         * Reads new data received from the given remote XBee device during the 
1572         * provided timeout.
1573         * 
1574         * <p>This method blocks until new data from the provided remote XBee 
1575         * device is received or the given timeout expires.</p>
1576         * 
1577         * <p>For non-blocking operations, register a {@code IDataReceiveListener} 
1578         * using the method {@link #addDataListener(IDataReceiveListener)}.</p>
1579         * 
1580         * @param remoteXBeeDevice The remote device to read data from.
1581         * @param timeout The time to wait for new data in milliseconds.
1582         * 
1583         * @return An {@code XBeeMessage} object containing the data and the source
1584         *         address of the remote node that sent the data. {@code null} if 
1585         *         this device did not receive new data from the provided remote 
1586         *         XBee device during {@code timeout} milliseconds.
1587         * 
1588         * @throws IllegalArgumentException if {@code timeout < 0}.
1589         * @throws InterfaceNotOpenException if this device connection is not open.
1590         * @throws NullPointerException if {@code remoteXBeeDevice == null}.
1591         * 
1592         * @see #readDataFrom(RemoteXBeeDevice)
1593         * @see #getReceiveTimeout()
1594         * @see #setReceiveTimeout(int)
1595         * @see #readData()
1596         * @see #readData(int)
1597         * @see RemoteXBeeDevice
1598         * @see com.digi.xbee.api.models.XBeeMessage
1599         */
1600        public XBeeMessage readDataFrom(RemoteXBeeDevice remoteXBeeDevice, int timeout) {
1601                if (remoteXBeeDevice == null)
1602                        throw new NullPointerException("Remote XBee device cannot be null.");
1603                if (timeout < 0)
1604                        throw new IllegalArgumentException("Read timeout must be 0 or greater.");
1605                
1606                return readDataPacket(remoteXBeeDevice, timeout);
1607        }
1608        
1609        /**
1610         * Reads a new data packet received by this XBee device during the provided 
1611         * timeout.
1612         * 
1613         * <p>This method blocks until new data is received or the given timeout 
1614         * expires.</p>
1615         * 
1616         * <p>If the provided remote XBee device is {@code null} the method returns 
1617         * the first data packet read from any remote device.
1618         * <br>
1619         * If the remote device is not {@code null} the method returns the first 
1620         * data package read from the provided device.
1621         * </p>
1622         * 
1623         * @param remoteXBeeDevice The remote device to get a data packet from. 
1624         *                         {@code null} to read a data packet sent by any 
1625         *                         remote XBee device.
1626         * @param timeout The time to wait for a data packet in milliseconds.
1627         * 
1628         * @return An {@code XBeeMessage} received by this device, containing the 
1629         *         data and the source address of the remote node that sent the 
1630         *         data. {@code null} if this device did not receive new data 
1631         *         during {@code timeout} milliseconds, or if any error occurs while
1632         *         trying to get the source of the message.
1633         * 
1634         * @throws InterfaceNotOpenException if this device connection is not open.
1635         * 
1636         * @see RemoteXBeeDevice
1637         * @see com.digi.xbee.api.models.XBeeMessage
1638         */
1639        private XBeeMessage readDataPacket(RemoteXBeeDevice remoteXBeeDevice, int timeout) {
1640                // Check connection.
1641                if (!connectionInterface.isOpen())
1642                        throw new InterfaceNotOpenException();
1643                
1644                XBeePacketsQueue xbeePacketsQueue = dataReader.getXBeePacketsQueue();
1645                XBeePacket xbeePacket = null;
1646                
1647                if (remoteXBeeDevice != null)
1648                        xbeePacket = xbeePacketsQueue.getFirstDataPacketFrom(remoteXBeeDevice, timeout);
1649                else
1650                        xbeePacket = xbeePacketsQueue.getFirstDataPacket(timeout);
1651                
1652                if (xbeePacket == null)
1653                        return null;
1654                
1655                // Obtain the remote device from the packet.
1656                RemoteXBeeDevice remoteDevice = null;
1657                try {
1658                        remoteDevice = dataReader.getRemoteXBeeDeviceFromPacket((XBeeAPIPacket)xbeePacket);
1659                        // If the provided device is not null, add it to the network, so the 
1660                        // device provided is the one that will remain in the network.
1661                        if (remoteXBeeDevice != null)
1662                                remoteDevice = getNetwork().addRemoteDevice(remoteXBeeDevice);
1663                        
1664                        // The packet always contains information of the source so the 
1665                        // remote device should never be null.
1666                        if (remoteDevice == null)
1667                                return null;
1668                        
1669                } catch (XBeeException e) {
1670                        logger.error(e.getMessage(), e);
1671                        return null;
1672                }
1673                
1674                // Obtain the data from the packet.
1675                byte[] data = null;
1676                
1677                switch (((XBeeAPIPacket)xbeePacket).getFrameType()) {
1678                        case RECEIVE_PACKET:
1679                                ReceivePacket receivePacket = (ReceivePacket)xbeePacket;
1680                                data = receivePacket.getRFData();
1681                                break;
1682                        case RX_16:
1683                                RX16Packet rx16Packet = (RX16Packet)xbeePacket;
1684                                data = rx16Packet.getRFData();
1685                                break;
1686                        case RX_64:
1687                                RX64Packet rx64Packet = (RX64Packet)xbeePacket;
1688                                data = rx64Packet.getRFData();
1689                                break;
1690                        default:
1691                                return null;
1692                        }
1693                
1694                // Create and return the XBee message.
1695                return new XBeeMessage(remoteDevice, data, ((XBeeAPIPacket)xbeePacket).isBroadcast());
1696        }
1697        
1698        /**
1699         * Reads new explicit data received by this XBee device during the 
1700         * configured receive timeout.
1701         * 
1702         * <p>This method blocks until new explicit data is received or the 
1703         * configured receive timeout expires.</p>
1704         * 
1705         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
1706         * method and can be consulted with {@code getReceiveTimeout} method.</p>
1707         * 
1708         * <p>For non-blocking operations, register a 
1709         * {@code IExplicitDataReceiveListener} using the method 
1710         * {@link #addExplicitDataListener(IExplicitDataReceiveListener)}.</p>
1711         * 
1712         * @return An {@code ExplicitXBeeMessage} object containing the explicit 
1713         *         data, the source address of the remote node that sent the data 
1714         *         and other values related to the transmission. {@code null} if 
1715         *         this did not receive new explicit data during the configured 
1716         *         receive timeout.
1717         * 
1718         * @throws InterfaceNotOpenException if this device connection is not open.
1719         * 
1720         * @see #getReceiveTimeout()
1721         * @see #readExplicitData(int)
1722         * @see #readExplicitDataFrom(RemoteXBeeDevice)
1723         * @see #readExplicitDataFrom(RemoteXBeeDevice, int)
1724         * @see #setReceiveTimeout(int)
1725         * @see com.digi.xbee.api.models.ExplicitXBeeMessage
1726         */
1727        protected ExplicitXBeeMessage readExplicitData() {
1728                return readExplicitDataPacket(null, TIMEOUT_READ_PACKET);
1729        }
1730        
1731        /**
1732         * Reads new explicit data received by this XBee device during the provided 
1733         * timeout.
1734         * 
1735         * <p>This method blocks until new explicit data is received or the 
1736         * provided timeout expires.</p>
1737         * 
1738         * <p>For non-blocking operations, register a 
1739         * {@code IExplicitDataReceiveListener} using the method 
1740         * {@link #addExplicitDataListener(IExplicitDataReceiveListener)}.</p>
1741         * 
1742         * @param timeout The time to wait for new explicit data in milliseconds.
1743         * 
1744         * @return An {@code ExplicitXBeeMessage} object containing the explicit 
1745         *         data, the source address of the remote node that sent the data 
1746         *         and other values related to the transmission. {@code null} if 
1747         *         this device did not receive new explicit data during 
1748         *         {@code timeout} milliseconds.
1749         * 
1750         * @throws IllegalArgumentException if {@code timeout < 0}.
1751         * @throws InterfaceNotOpenException if this device connection is not open.
1752         * 
1753         * @see #readExplicitData()
1754         * @see #readExplicitDataFrom(RemoteXBeeDevice)
1755         * @see #readExplicitDataFrom(RemoteXBeeDevice, int)
1756         * @see com.digi.xbee.api.models.ExplicitXBeeMessage
1757         */
1758        protected ExplicitXBeeMessage readExplicitData(int timeout) {
1759                if (timeout < 0)
1760                        throw new IllegalArgumentException("Read timeout must be 0 or greater.");
1761                
1762                return readExplicitDataPacket(null, timeout);
1763        }
1764        
1765        /**
1766         * Reads new explicit data received from the given remote XBee device 
1767         * during the configured receive timeout.
1768         * 
1769         * <p>This method blocks until new explicit data from the provided remote 
1770         * XBee device is received or the configured receive timeout expires.</p>
1771         * 
1772         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
1773         * method and can be consulted with {@code getReceiveTimeout} method.</p>
1774         * 
1775         * <p>For non-blocking operations, register a 
1776         * {@code IExplicitDataReceiveListener} using the method 
1777         * {@link #addExplicitDataListener(IExplicitDataReceiveListener)}.</p>
1778         * 
1779         * @param remoteXBeeDevice The remote device to read explicit data from.
1780         * 
1781         * @return An {@code ExplicitXBeeMessage} object containing the explicit 
1782         *         data, the source address of the remote node that sent the data 
1783         *         and other values related to the transmission. {@code null} if 
1784         *         this device did not receive new explicit data from the provided 
1785         *         remote XBee device during the configured receive timeout.
1786         * 
1787         * @throws InterfaceNotOpenException if this device connection is not open.
1788         * @throws NullPointerException if {@code remoteXBeeDevice == null}.
1789         * 
1790         * @see #getReceiveTimeout()
1791         * @see #readExplicitData()
1792         * @see #readExplicitData(int)
1793         * @see #readExplicitDataFrom(RemoteXBeeDevice, int)
1794         * @see #setReceiveTimeout(int)
1795         * @see RemoteXBeeDevice
1796         * @see com.digi.xbee.api.models.ExplicitXBeeMessage
1797         */
1798        protected ExplicitXBeeMessage readExplicitDataFrom(RemoteXBeeDevice remoteXBeeDevice) {
1799                if (remoteXBeeDevice == null)
1800                        throw new NullPointerException("Remote XBee device cannot be null.");
1801                
1802                return readExplicitDataPacket(remoteXBeeDevice, TIMEOUT_READ_PACKET);
1803        }
1804        
1805        /**
1806         * Reads new explicit data received from the given remote XBee device 
1807         * during the provided timeout.
1808         * 
1809         * <p>This method blocks until new explicit data from the provided remote 
1810         * XBee device is received or the given timeout expires.</p>
1811         * 
1812         * <p>For non-blocking operations, register a 
1813         * {@code IExplicitDataReceiveListener} using the method 
1814         * {@link #addExplicitDataListener(IExplicitDataReceiveListener)}.</p>
1815         * 
1816         * @param remoteXBeeDevice The remote device to read explicit data from.
1817         * @param timeout The time to wait for new explicit data in milliseconds.
1818         * 
1819         * @return An {@code ExplicitXBeeMessage} object containing the explicit 
1820         *         data, the source address of the remote node that sent the data 
1821         *         and other values related to the transmission. {@code null} if 
1822         *         this device did not receive new data from the provided remote 
1823         *         XBee device during {@code timeout} milliseconds.
1824         * 
1825         * @throws IllegalArgumentException if {@code timeout < 0}.
1826         * @throws InterfaceNotOpenException if this device connection is not open.
1827         * @throws NullPointerException if {@code remoteXBeeDevice == null}.
1828         * 
1829         * @see #getReceiveTimeout()
1830         * @see #readExplicitData()
1831         * @see #readExplicitData(int)
1832         * @see #readExplicitDataFrom(RemoteXBeeDevice)
1833         * @see #setReceiveTimeout(int)
1834         * @see RemoteXBeeDevice
1835         * @see com.digi.xbee.api.models.ExplicitXBeeMessage
1836         */
1837        protected ExplicitXBeeMessage readExplicitDataFrom(RemoteXBeeDevice remoteXBeeDevice, int timeout) {
1838                if (remoteXBeeDevice == null)
1839                        throw new NullPointerException("Remote XBee device cannot be null.");
1840                if (timeout < 0)
1841                        throw new IllegalArgumentException("Read timeout must be 0 or greater.");
1842                
1843                return readExplicitDataPacket(remoteXBeeDevice, timeout);
1844        }
1845        
1846        /**
1847         * Reads a new explicit data packet received by this XBee device during 
1848         * the provided timeout.
1849         * 
1850         * <p>This method blocks until new explicit data is received or the given 
1851         * timeout expires.</p>
1852         * 
1853         * <p>If the provided remote XBee device is {@code null} the method returns 
1854         * the first explicit data packet read from any remote device.
1855         * <br>
1856         * If the remote device is not {@code null} the method returns the first 
1857         * explicit data package read from the provided device.
1858         * </p>
1859         * 
1860         * @param remoteXBeeDevice The remote device to get an explicit data 
1861         *                         packet from. {@code null} to read an explicit 
1862         *                         data packet sent by any remote XBee device.
1863         * @param timeout The time to wait for an explicit data packet in 
1864         *                milliseconds.
1865         * 
1866         * @return An {@code XBeeMessage} received by this device, containing the 
1867         *         explicit data and the source address of the remote node that 
1868         *         sent the data. {@code null} if this device did not receive new 
1869         *         explicit data during {@code timeout} milliseconds.
1870         * 
1871         * @throws InterfaceNotOpenException if this device connection is not open.
1872         * 
1873         * @see RemoteXBeeDevice
1874         * @see com.digi.xbee.api.models.ExplicitXBeeMessage
1875         */
1876        private ExplicitXBeeMessage readExplicitDataPacket(RemoteXBeeDevice remoteXBeeDevice, int timeout) {
1877                // Check connection.
1878                if (!connectionInterface.isOpen())
1879                        throw new InterfaceNotOpenException();
1880                
1881                XBeePacketsQueue xbeePacketsQueue = dataReader.getXBeePacketsQueue();
1882                XBeePacket xbeePacket = null;
1883                
1884                if (remoteXBeeDevice != null)
1885                        xbeePacket = xbeePacketsQueue.getFirstExplicitDataPacketFrom(remoteXBeeDevice, timeout);
1886                else
1887                        xbeePacket = xbeePacketsQueue.getFirstExplicitDataPacket(timeout);
1888                
1889                if (xbeePacket == null)
1890                        return null;
1891                
1892                // Verify the packet is an explicit data packet.
1893                APIFrameType packetType = ((XBeeAPIPacket)xbeePacket).getFrameType();
1894                if (packetType != APIFrameType.EXPLICIT_RX_INDICATOR)
1895                        return null;
1896                
1897                // Obtain the necessary data from the packet.
1898                ExplicitRxIndicatorPacket explicitDataPacket = (ExplicitRxIndicatorPacket)xbeePacket;
1899                RemoteXBeeDevice remoteDevice = getNetwork().getDevice(explicitDataPacket.get64BitSourceAddress());
1900                if (remoteDevice == null) {
1901                        if (remoteXBeeDevice != null)
1902                                remoteDevice = remoteXBeeDevice;
1903                        else
1904                                remoteDevice = new RemoteXBeeDevice(this, explicitDataPacket.get64BitSourceAddress());
1905                        getNetwork().addRemoteDevice(remoteDevice);
1906                }
1907                int sourceEndpoint = explicitDataPacket.getSourceEndpoint();
1908                int destEndpoint = explicitDataPacket.getDestinationEndpoint();
1909                int clusterID = explicitDataPacket.getClusterID();
1910                int profileID = explicitDataPacket.getProfileID();
1911                byte[] data = explicitDataPacket.getRFData();
1912                
1913                // Create and return the XBee message.
1914                return new ExplicitXBeeMessage(remoteDevice, sourceEndpoint, destEndpoint, clusterID, profileID, data, ((XBeeAPIPacket)xbeePacket).isBroadcast());
1915        }
1916        
1917        /**
1918         * Configures the API output mode of the XBee device.
1919         * 
1920         * <p>The API output mode determines the format that the received data is 
1921         * output through the serial interface of the XBee device.</p>
1922         * 
1923         * @param apiOutputMode The API output mode to be set to the XBee device.
1924         * 
1925         * @throws InterfaceNotOpenException if this device connection is not open.
1926         * @throws NullPointerException if {@code apiOutputMode == null}.
1927         * @throws TimeoutException if there is a timeout configuring the API 
1928         *                          output mode.
1929         * @throws XBeeException if there is any other XBee related exception.
1930         * 
1931         * @see #getAPIOutputMode()
1932         * @see APIOutputMode
1933         */
1934        protected void setAPIOutputMode(APIOutputMode apiOutputMode) throws TimeoutException, XBeeException {
1935                if (apiOutputMode == null)
1936                        throw new NullPointerException("API output mode cannot be null.");
1937                
1938                setParameter("AO", new byte[]{(byte)apiOutputMode.getValue()});
1939        }
1940        
1941        /**
1942         * Returns the API output mode of the XBee device.
1943         * 
1944         * <p>The API output mode determines the format that the received data is 
1945         * output through the serial interface of the XBee device.</p>
1946         * 
1947         * @return The API output mode that the XBee device is configured with.
1948         * 
1949         * @throws InterfaceNotOpenException if this device connection is not open.
1950         * @throws TimeoutException if there is a timeout getting the API output 
1951         *                          mode from the device.
1952         * @throws XBeeException if there is any other XBee related exception.
1953         * 
1954         * @see #setAPIOutputMode(APIOutputMode)
1955         * @see APIOutputMode
1956         */
1957        protected APIOutputMode getAPIOutputMode() throws TimeoutException, XBeeException {
1958                byte[] apiOutputModeValue = getParameter("AO");
1959                
1960                return APIOutputMode.get(apiOutputModeValue[0]);
1961        }
1962        
1963        /*
1964         * (non-Javadoc)
1965         * @see com.digi.xbee.api.AbstractXBeeDevice#toString()
1966         */
1967        @Override
1968        public String toString() {
1969                String id = getNodeID() == null ? "" : getNodeID();
1970                String addr64 = get64BitAddress() == null || get64BitAddress() == XBee64BitAddress.UNKNOWN_ADDRESS ? 
1971                                "" : get64BitAddress().toString();
1972                
1973                if (id.length() == 0 && addr64.length() == 0)
1974                        return super.toString();
1975                
1976                StringBuilder message = new StringBuilder(super.toString());
1977                message.append(addr64);
1978                if (id.length() > 0) {
1979                        message.append(" (");
1980                        message.append(id);
1981                        message.append(")");
1982                }
1983                message.append(" - ");
1984                
1985                return message.toString();
1986        }
1987}