    001/**
    002 * Copyright (c) 2014 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.InterfaceAlreadyOpenException;
    020import com.digi.xbee.api.exceptions.InterfaceNotOpenException;
    021import com.digi.xbee.api.exceptions.InvalidOperatingModeException;
    022import com.digi.xbee.api.exceptions.OperationNotSupportedException;
    023import com.digi.xbee.api.exceptions.TimeoutException;
    024import com.digi.xbee.api.exceptions.XBeeException;
    025import com.digi.xbee.api.listeners.IIOSampleReceiveListener;
    026import com.digi.xbee.api.listeners.IModemStatusReceiveListener;
    027import com.digi.xbee.api.listeners.IPacketReceiveListener;
    028import com.digi.xbee.api.listeners.IDataReceiveListener;
    029import com.digi.xbee.api.models.ATCommand;
    030import com.digi.xbee.api.models.ATCommandResponse;
    031import com.digi.xbee.api.models.ModemStatusEvent;
    032import com.digi.xbee.api.models.OperatingMode;
    033import com.digi.xbee.api.models.XBee16BitAddress;
    034import com.digi.xbee.api.models.XBee64BitAddress;
    035import com.digi.xbee.api.models.XBeeMessage;
    036import com.digi.xbee.api.models.XBeePacketsQueue;
    037import com.digi.xbee.api.models.XBeeTransmitOptions;
    038import com.digi.xbee.api.packet.APIFrameType;
    039import com.digi.xbee.api.packet.XBeeAPIPacket;
    040import com.digi.xbee.api.packet.XBeePacket;
    041import com.digi.xbee.api.packet.common.ReceivePacket;
    042import com.digi.xbee.api.packet.common.TransmitPacket;
    043import com.digi.xbee.api.packet.raw.RX16Packet;
    044import com.digi.xbee.api.packet.raw.RX64Packet;
    045import com.digi.xbee.api.packet.raw.TX64Packet;
    046import com.digi.xbee.api.utils.HexUtils;
    047
    048/**
    049 * This class represents a local XBee device.
    050 *
    051 * @see DigiMeshDevice
    052 * @see DigiPointDevice
    053 * @see Raw802Device
    054 * @see ZigBeeDevice
    055 */
    056public class XBeeDevice extends AbstractXBeeDevice {
    057
    058        // Constants.
    059        private static int TIMEOUT_RESET = 5000;
    060        private static int TIMEOUT_READ_PACKET = 3000;
    061
    062        private static String COMMAND_MODE_CHAR = "+";
    063        private static String COMMAND_MODE_OK = "OK\r";
    064
    065        // Variables.
    066        protected XBeeNetwork network;
    067
    068        private Object resetLock = new Object();
    069
    070        private boolean modemStatusReceived = false;
    071
    072        /**
    073         * Class constructor. Instantiates a new {@code XBeeDevice} object
    074         * physically connected to the given port name and configured at the
    075         * provided baud rate.
    076         *
    077         * @param port Serial port name where XBee device is attached to.
    078         * @param baudRate Serial port baud rate to communicate with the device.
    079         *                 Other connection parameters will be set as default (8
    080         *                 data bits, 1 stop bit, no parity, no flow control).
    081         *
    082         * @throws IllegalArgumentException if {@code baudRate < 0}.
    083         * @throws NullPointerException if {@code port == null}.
    084         *
    085         * @see #XBeeDevice(IConnectionInterface)
    086         * @see #XBeeDevice(String, SerialPortParameters)
    087         * @see #XBeeDevice(String, int, int, int, int, int)
    088         */
    089        public XBeeDevice(String port, int baudRate) {
    090                super(port, baudRate);
    091        }
    092
    093        /**
    094         * Class constructor. Instantiates a new {@code XBeeDevice} object
    095         * physically connected to the given port name and configured to communicate
    096         * with the provided serial settings.
    097         *
    098         * @param port Serial port name where XBee device is attached to.
    099         * @param baudRate Serial port baud rate to communicate with the device.
    100         * @param dataBits Serial port data bits.
    101         * @param stopBits Serial port data bits.
    102         * @param parity Serial port data bits.
    103         * @param flowControl Serial port data bits.
    104         *
    105         * @throws IllegalArgumentException if {@code baudRate < 0} or
    106         *                                  if {@code dataBits < 0} or
    107         *                                  if {@code stopBits < 0} or
    108         *                                  if {@code parity < 0} or
    109         *                                  if {@code flowControl < 0}.
    110         * @throws NullPointerException if {@code port == null}.
    111         *
    112         * @see #XBeeDevice(IConnectionInterface)
    113         * @see #XBeeDevice(String, int)
    114         * @see #XBeeDevice(String, SerialPortParameters)
    115         */
    116        public XBeeDevice(String port, int baudRate, int dataBits, int stopBits, int parity, int flowControl) {
    117                super(port, baudRate, dataBits, stopBits, parity, flowControl);
    118        }
    119
    120        /**
    121         * Class constructor. Instantiates a new {@code XBeeDevice} object
    122         * physically connected to the given port name and configured to communicate
    123         * with the provided serial settings.
    124         *
    125         * @param port Serial port name where XBee device is attached to.
    126         * @param serialPortParameters Object containing the serial port parameters.
    127         *
    128         * @throws NullPointerException if {@code port == null} or
    129         *                              if {@code serialPortParameters == null}.
    130         *
    131         * @see #XBeeDevice(IConnectionInterface)
    132         * @see #XBeeDevice(String, int)
    133         * @see #XBeeDevice(String, int, int, int, int, int)
    134         * @see com.digi.xbee.api.connection.serial.SerialPortParameters
    135         */
    136        public XBeeDevice(String port, SerialPortParameters serialPortParameters) {
    137                super(port, serialPortParameters);
    138        }
    139
    140        /**
    141         * Class constructor. Instantiates a new {@code XBeeDevice} object with the
    142         * given connection interface.
    143         *
    144         * @param connectionInterface The connection interface with the physical
    145         *                            XBee device.
    146         *
    147         * @throws NullPointerException if {@code connectionInterface == null}.
    148         *
    149         * @see #XBeeDevice(String, int)
    150         * @see #XBeeDevice(String, SerialPortParameters)
    151         * @see #XBeeDevice(String, int, int, int, int, int)
    152         * @see com.digi.xbee.api.connection.IConnectionInterface
    153         */
    154        public XBeeDevice(IConnectionInterface connectionInterface) {
    155                super(connectionInterface);
    156        }
    157
    158        /**
    159         * Opens the connection interface associated with this XBee device.
    160         *
    161         * <p>When opening the device an information reading process is
    162         * automatically performed. This includes:</p>
    163         *
    164         * <ul>
    165         * <li>64-bit address.</li>
    166         * <li>Node Identifier.</li>
    167         * <li>Hardware version.</li>
    168         * <li>Firmware version.</li>
    169         * <li>XBee device protocol.</li>
    170         * <li>16-bit address (not for DigiMesh modules).</li>
    171         * </ul>
    172         *
    173         * @throws InterfaceAlreadyOpenException if this device connection is
    174         *                                       already open.
    175         * @throws XBeeException if there is any problem opening this device
    176         *                       connection.
    177         *
    178         * @see #close()
    179         * @see #isOpen()
    180         */
    181        public void open() throws XBeeException {
    182                logger.info(toString() + "Opening the connection interface...");
    183
    184                // First, verify that the connection is not already open.
    185                if (connectionInterface.isOpen())
    186                        throw new InterfaceAlreadyOpenException();
    187
    188                // Connect the interface.
    189                connectionInterface.open();
    190
    191                logger.info(toString() + "Connection interface open.");
    192
    193                // Initialize the data reader.
    194                dataReader = new DataReader(connectionInterface, operatingMode, this);
    195                dataReader.start();
    196
    197                // Wait 10 milliseconds until the dataReader thread is started.
    198                // This is because when the connection is opened immediately after
    199                // closing it, there is sometimes a concurrency problem and the
    200                // dataReader thread never dies.
    201                try {
    202                        Thread.sleep(10);
    203                } catch (InterruptedException e) {}
    204
    205                // Determine the operating mode of the XBee device if it is unknown.
    206                if (operatingMode == OperatingMode.UNKNOWN)
    207                        operatingMode = determineOperatingMode();
    208
    209                // Check if the operating mode is a valid and supported one.
    210                if (operatingMode == OperatingMode.UNKNOWN) {
    211                        close();
    212                        throw new InvalidOperatingModeException("Could not determine operating mode.");
    213                } else if (operatingMode == OperatingMode.AT) {
    214                        close();
    215                        throw new InvalidOperatingModeException(operatingMode);
    216                }
    217
    218                // Read the device info (obtain its parameters and protocol).
    219                readDeviceInfo();
    220        }
    221
    222        /**
    223         * Closes the connection interface associated with this XBee device.
    224         *
    225         * @see #isOpen()
    226         * @see #open()
    227         */
    228        public void close() {
    229                // Stop XBee reader.
    230                if (dataReader != null && dataReader.isRunning())
    231                        dataReader.stopReader();
    232                // Close interface.
    233                connectionInterface.close();
    234                logger.info(toString() + "Connection interface closed.");
    235        }
    236
    237        /**
    238         * Returns whether the connection interface associated to this device is
    239         * already open.
    240         *
    241         * @return {@code true} if the interface is open, {@code false} otherwise.
    242         *
    243         * @see #close()
    244         * @see #open()
    245         */
    246        public boolean isOpen() {
    247                if (connectionInterface != null)
    248                        return connectionInterface.isOpen();
    249                return false;
    250        }
    251
    252        /**
    253         * Always returns {@code false}, since this is always a local device.
    254         *
    255         * @return {@code false} since it is a local device.
    256         */
    257        @Override
    258        public boolean isRemote() {
    259                return false;
    260        }
    261
    262        /**
    263         * Returns the network associated with this XBee device.
    264         *
    265         * @return The XBee network of the device.
    266         *
    267         * @throws InterfaceNotOpenException if this device connection is not open.
    268         *
    269         * @see XBeeNetwork
    270         */
    271        public XBeeNetwork getNetwork() {
    272                if (!isOpen())
    273                        throw new InterfaceNotOpenException();
    274
    275                if (network == null)
    276                        network = new XBeeNetwork(this);
    277                return network;
    278        }
    279
    280        /**
    281         * Returns the Operating mode (AT, API or API escaped) of this XBee device.
    282         *
    283         * @return The operating mode of this XBee device.
    284         *
    285         * @see com.digi.xbee.api.models.OperatingMode
    286         */
    287        @Override
    288        public OperatingMode getOperatingMode() {
    289                return super.getOperatingMode();
    290        }
    291
    292        /*
    293         * (non-Javadoc)
    294         * @see com.digi.xbee.api.AbstractXBeeDevice#getNextFrameID()
    295         */
    296        @Override
    297        protected int getNextFrameID() {
    298                return super.getNextFrameID();
    299        }
    300
    301        /**
    302         * Returns this XBee device configured timeout for receiving packets in
    303         * synchronous operations.
    304         *
    305         * @return The current receive timeout in milliseconds.
    306         *
    307         * @see #setReceiveTimeout(int)
    308         */
    309        public int getReceiveTimeout() {
    310                return receiveTimeout;
    311        }
    312
    313        /**
    314         * Configures this XBee device timeout in milliseconds for receiving
    315         * packets in synchronous operations.
    316         *
    317         * @param receiveTimeout The new receive timeout in milliseconds.
    318         *
    319         * @throws IllegalArgumentException if {@code receiveTimeout < 0}.
    320         *
    321         * @see #getReceiveTimeout()
    322         */
    323        public void setReceiveTimeout(int receiveTimeout) {
    324                if (receiveTimeout < 0)
    325                        throw new IllegalArgumentException("Receive timeout cannot be less than 0.");
    326
    327                this.receiveTimeout = receiveTimeout;
    328        }
    329
    330        /**
    331         * Determines the operating mode of this XBee device.
    332         *
    333         * @return The operating mode of the XBee device.
    334         *
    335         * @throws InterfaceNotOpenException if this device connection is not open.
    336         * @throws OperationNotSupportedException if the packet is being sent from
    337         *                                        a remote device.
    338         *
    339         * @see com.digi.xbee.api.models.OperatingMode
    340         */
    341        protected OperatingMode determineOperatingMode() throws OperationNotSupportedException {
    342                try {
    343                        // Check if device is in API or API Escaped operating modes.
    344                        operatingMode = OperatingMode.API;
    345                        dataReader.setXBeeReaderMode(operatingMode);
    346
    347                        ATCommandResponse response = sendATCommand(new ATCommand("AP"));
    348                        if (response.getResponse() != null && response.getResponse().length > 0) {
    349                                if (response.getResponse()[0] != OperatingMode.API.getID())
    350                                        operatingMode = OperatingMode.API_ESCAPE;
    351                                logger.debug(toString() + "Using {}.", operatingMode.getName());
    352                                return operatingMode;
    353                        }
    354                } catch (TimeoutException e) {
    355                        // Check if device is in AT operating mode.
    356                        operatingMode = OperatingMode.AT;
    357                        dataReader.setXBeeReaderMode(operatingMode);
    358
    359                        try {
    360                                // It is necessary to wait at least 1 second to enter in
    361                                // command mode after sending any data to the device.
    362                                Thread.sleep(TIMEOUT_BEFORE_COMMAND_MODE);
    363                                // Try to enter in AT command mode, if so the module is in AT mode.
    364                                boolean success = enterATCommandMode();
    365                                if (success)
    366                                        return OperatingMode.AT;
    367                        } catch (TimeoutException e1) {
    368                                logger.error(e1.getMessage(), e1);
    369                        } catch (InvalidOperatingModeException e1) {
    370                                logger.error(e1.getMessage(), e1);
    371                        } catch (InterruptedException e1) {
    372                                logger.error(e1.getMessage(), e1);
    373                        }
    374                } catch (InvalidOperatingModeException e) {
    375                        logger.error("Invalid operating mode", e);
    376                } catch (IOException e) {
    377                        logger.error(e.getMessage(), e);
    378                }
    379                return OperatingMode.UNKNOWN;
    380        }
    381
    382        /**
    383         * Attempts to put this device in AT Command mode. Only valid if device is
    384         * working in AT mode.
    385         *
    386         * @return {@code true} if the device entered in AT command mode,
    387         *         {@code false} otherwise.
    388         *
    389         * @throws InterfaceNotOpenException if this device connection is not open.
    390         * @throws InvalidOperatingModeException if the operating mode cannot be
    391         *                                       determined or is not supported.
    392         * @throws TimeoutException if the configured time for this device expires.
    393         */
    394        private boolean enterATCommandMode() throws InvalidOperatingModeException, TimeoutException {
    395                if (!connectionInterface.isOpen())
    396                        throw new InterfaceNotOpenException();
    397                if (operatingMode != OperatingMode.AT)
    398                        throw new InvalidOperatingModeException("Invalid mode. Command mode can be only accessed while in AT mode.");
    399
    400                // Enter in AT command mode (send '+++'). The process waits 1,5 seconds for the 'OK\n'.
    401                byte[] readData = new byte[256];
    402                try {
    403                        // Send the command mode sequence.
    404                        connectionInterface.writeData(COMMAND_MODE_CHAR.getBytes());
    405                        connectionInterface.writeData(COMMAND_MODE_CHAR.getBytes());
    406                        connectionInterface.writeData(COMMAND_MODE_CHAR.getBytes());
    407
    408                        // Wait some time to let the module generate a response.
    409                        Thread.sleep(TIMEOUT_ENTER_COMMAND_MODE);
    410
    411                        // Read data from the device (it should answer with 'OK\r').
    412                        int readBytes = connectionInterface.readData(readData);
    413                        if (readBytes < COMMAND_MODE_OK.length())
    414                                throw new TimeoutException();
    415
    416                        // Check if the read data is 'OK\r'.
    417                        String readString = new String(readData, 0, readBytes);
    418                        if (!readString.contains(COMMAND_MODE_OK))
    419                                return false;
    420
    421                        // Read data was 'OK\r'.
    422                        return true;
    423                } catch (IOException e) {
    424                        logger.error(e.getMessage(), e);
    425                } catch (InterruptedException e) {
    426                        logger.error(e.getMessage(), e);
    427                }
    428                return false;
    429        }
    430
    431        /*
    432         * (non-Javadoc)
    433         * @see com.digi.xbee.api.AbstractXBeeDevice#addPacketListener(com.digi.xbee.api.listeners.IPacketReceiveListener)
    434         */
    435        @Override
    436        public void addPacketListener(IPacketReceiveListener listener) {
    437                super.addPacketListener(listener);
    438        }
    439
    440        /*
    441         * (non-Javadoc)
    442         * @see com.digi.xbee.api.AbstractXBeeDevice#removePacketListener(com.digi.xbee.api.listeners.IPacketReceiveListener)
    443         */
    444        @Override
    445        public void removePacketListener(IPacketReceiveListener listener) {
    446                super.removePacketListener(listener);
    447        }
    448
    449        /*
    450         * (non-Javadoc)
    451         * @see com.digi.xbee.api.AbstractXBeeDevice#addDataListener(com.digi.xbee.api.listeners.IDataReceiveListener)
    452         */
    453        @Override
    454        public void addDataListener(IDataReceiveListener listener) {
    455                super.addDataListener(listener);
    456        }
    457
    458        /*
    459         * (non-Javadoc)
    460         * @see com.digi.xbee.api.AbstractXBeeDevice#removeDataListener(com.digi.xbee.api.listeners.IDataReceiveListener)
    461         */
    462        @Override
    463        public void removeDataListener(IDataReceiveListener listener) {
    464                super.removeDataListener(listener);
    465        }
    466
    467        /*
    468         * (non-Javadoc)
    469         * @see com.digi.xbee.api.AbstractXBeeDevice#addIOSampleListener(com.digi.xbee.api.listeners.IIOSampleReceiveListener)
    470         */
    471        @Override
    472        public void addIOSampleListener(IIOSampleReceiveListener listener) {
    473                super.addIOSampleListener(listener);
    474        }
    475
    476        /*
    477         * (non-Javadoc)
    478         * @see com.digi.xbee.api.AbstractXBeeDevice#removeIOSampleListener(com.digi.xbee.api.listeners.IIOSampleReceiveListener)
    479         */
    480        @Override
    481        public void removeIOSampleListener(IIOSampleReceiveListener listener) {
    482                super.removeIOSampleListener(listener);
    483        }
    484
    485        /*
    486         * (non-Javadoc)
    487         * @see com.digi.xbee.api.AbstractXBeeDevice#addModemStatusListener(com.digi.xbee.api.listeners.IModemStatusReceiveListener)
    488         */
    489        @Override
    490        public void addModemStatusListener(IModemStatusReceiveListener listener) {
    491                super.addModemStatusListener(listener);
    492        }
    493
    494        /*
    495         * (non-Javadoc)
    496         * @see com.digi.xbee.api.AbstractXBeeDevice#removeModemStatusListener(com.digi.xbee.api.listeners.IModemStatusReceiveListener)
    497         */
    498        @Override
    499        public void removeModemStatusListener(IModemStatusReceiveListener listener) {
    500                super.removeModemStatusListener(listener);
    501        }
    502
    503        /**
    504         * Sends asynchronously the provided data to the XBee device of the network
    505         * corresponding to the given 64-bit address.
    506         *
    507         * <p>Asynchronous transmissions do not wait for answer from the remote
    508         * device or for transmit status packet.</p>
    509         *
    510         * @param address The 64-bit address of the XBee that will receive the data.
    511         * @param data Byte array containing the data to be sent.
    512         *
    513         * @throws InterfaceNotOpenException if this device connection is not open.
    514         * @throws NullPointerException if {@code address == null} or
    515         *                              if {@code data == null}.
    516         * @throws XBeeException if there is any XBee related exception.
    517         *
    518         * @see #sendData(RemoteXBeeDevice, byte[])
    519         * @see #sendData(XBee64BitAddress, byte[])
    520         * @see #sendData(XBee64BitAddress, XBee16BitAddress, byte[])
    521         * @see #sendDataAsync(RemoteXBeeDevice, byte[])
    522         * @see #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[])
    523         * @see com.digi.xbee.api.models.XBee64BitAddress
    524         */
    525        protected void sendDataAsync(XBee64BitAddress address, byte[] data) throws XBeeException {
    526                // Verify the parameters are not null, if they are null, throw an exception.
    527                if (address == null)
    528                        throw new NullPointerException("Address cannot be null");
    529                if (data == null)
    530                        throw new NullPointerException("Data cannot be null");
    531
    532                // Check connection.
    533                if (!connectionInterface.isOpen())
    534                        throw new InterfaceNotOpenException();
    535                // Check if device is remote.
    536                if (isRemote())
    537                        throw new OperationNotSupportedException("Cannot send data to a remote device from a remote device.");
    538
    539                logger.debug(toString() + "Sending data asynchronously to {} >> {}.", address, HexUtils.prettyHexString(data));
    540
    541                XBeePacket xbeePacket;
    542                switch (getXBeeProtocol()) {
    543                case RAW_802_15_4:
    544                        xbeePacket = new TX64Packet(getNextFrameID(), address, XBeeTransmitOptions.NONE, data);
    545                        break;
    546                default:
    547                        xbeePacket = new TransmitPacket(getNextFrameID(), address, XBee16BitAddress.UNKNOWN_ADDRESS, 0, XBeeTransmitOptions.NONE, data);
    548                }
    549                sendAndCheckXBeePacket(xbeePacket, true);
    550        }
    551
    552        /**
    553         * Sends asynchronously the provided data to the XBee device of the network
    554         * corresponding to the given 64-bit/16-bit address.
    555         *
    556         * <p>Asynchronous transmissions do not wait for answer from the remote
    557         * device or for transmit status packet.</p>
    558         *
    559         * @param address64Bit The 64-bit address of the XBee that will receive the
    560         *                     data.
    561         * @param address16bit The 16-bit address of the XBee that will receive the
    562         *                     data. If it is unknown the
    563         *                     {@code XBee16BitAddress.UNKNOWN_ADDRESS} must be
    564         *                     used.
    565         * @param data Byte array containing the data to be sent.
    566         *
    567         * @throws InterfaceNotOpenException if this device connection is not open.
    568         * @throws NullPointerException if {@code address64Bit == null} or
    569         *                              if {@code address16bit == null} or
    570         *                              if {@code data == null}.
    571         * @throws XBeeException if a remote device is trying to send data or
    572         *                       if there is any other XBee related exception.
    573         *
    574         * @see #getReceiveTimeout()
    575         * @see #setReceiveTimeout(int)
    576         * @see #sendData(RemoteXBeeDevice, byte[])
    577         * @see #sendData(XBee64BitAddress, byte[])
    578         * @see #sendData(XBee64BitAddress, XBee16BitAddress, byte[])
    579         * @see #sendDataAsync(RemoteXBeeDevice, byte[])
    580         * @see #sendDataAsync(XBee64BitAddress, byte[])
    581         * @see com.digi.xbee.api.models.XBee16BitAddress
    582         * @see com.digi.xbee.api.models.XBee64BitAddress
    583         */
    584        protected void sendDataAsync(XBee64BitAddress address64Bit, XBee16BitAddress address16bit, byte[] data) throws XBeeException {
    585                // Verify the parameters are not null, if they are null, throw an exception.
    586                if (address64Bit == null)
    587                        throw new NullPointerException("64-bit address cannot be null");
    588                if (address16bit == null)
    589                        throw new NullPointerException("16-bit address cannot be null");
    590                if (data == null)
    591                        throw new NullPointerException("Data cannot be null");
    592
    593                // Check connection.
    594                if (!connectionInterface.isOpen())
    595                        throw new InterfaceNotOpenException();
    596                // Check if device is remote.
    597                if (isRemote())
    598                        throw new OperationNotSupportedException("Cannot send data to a remote device from a remote device.");
    599
    600                logger.debug(toString() + "Sending data asynchronously to {}[{}] >> {}.",
    601                                address64Bit, address16bit, HexUtils.prettyHexString(data));
    602
    603                XBeePacket xbeePacket = new TransmitPacket(getNextFrameID(), address64Bit, address16bit, 0, XBeeTransmitOptions.NONE, data);
    604                sendAndCheckXBeePacket(xbeePacket, true);
    605        }
    606
    607        /**
    608         * Sends the provided data to the provided XBee device asynchronously.
    609         *
    610         * <p>Asynchronous transmissions do not wait for answer from the remote
    611         * device or for transmit status packet.</p>
    612         *
    613         * @param xbeeDevice The XBee device of the network that will receive the
    614         *                   data.
    615         * @param data Byte array containing the data to be sent.
    616         *
    617         * @throws InterfaceNotOpenException if this device connection is not open.
    618         * @throws NullPointerException if {@code xbeeDevice == null} or
    619         *                              if {@code data == null}.
    620         * @throws XBeeException if there is any XBee related exception.
    621         *
    622         * @see #sendData(RemoteXBeeDevice, byte[])
    623         * @see RemoteXBeeDevice
    624         */
    625        public void sendDataAsync(RemoteXBeeDevice xbeeDevice, byte[] data) throws XBeeException {
    626                if (xbeeDevice == null)
    627                        throw new NullPointerException("Remote XBee device cannot be null");
    628                sendDataAsync(xbeeDevice.get64BitAddress(), data);
    629        }
    630
    631        /**
    632         * Sends the provided data to the XBee device of the network corresponding
    633         * to the given 64-bit address.
    634         *
    635         * <p>This method blocks till a success or error response arrives or the
    636         * configured receive timeout expires.</p>
    637         *
    638         * <p>The received timeout is configured using the {@code setReceiveTimeout}
    639         * method and can be consulted with {@code getReceiveTimeout} method.</p>
    640         *
    641         * <p>For non-blocking operations use the method
    642         * {@link #sendData(XBee64BitAddress, byte[])}.</p>
    643         *
    644         * @param address The 64-bit address of the XBee that will receive the data.
    645         * @param data Byte array containing the data to be sent.
    646         *
    647         * @throws InterfaceNotOpenException if this device connection is not open.
    648         * @throws NullPointerException if {@code address == null} or
    649         *                              if {@code data == null}.
    650         * @throws TimeoutException if there is a timeout sending the data.
    651         * @throws XBeeException if there is any other XBee related exception.
    652         *
    653         * @see #getReceiveTimeout()
    654         * @see #setReceiveTimeout(int)
    655         * @see #sendData(RemoteXBeeDevice, byte[])
    656         * @see #sendData(XBee64BitAddress, XBee16BitAddress, byte[])
    657         * @see #sendDataAsync(RemoteXBeeDevice, byte[])
    658         * @see #sendDataAsync(XBee64BitAddress, byte[])
    659         * @see #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[])
    660         * @see com.digi.xbee.api.models.XBee64BitAddress
    661         */
    662        protected void sendData(XBee64BitAddress address, byte[] data) throws TimeoutException, XBeeException {
    663                // Verify the parameters are not null, if they are null, throw an exception.
    664                if (address == null)
    665                        throw new NullPointerException("Address cannot be null");
    666                if (data == null)
    667                        throw new NullPointerException("Data cannot be null");
    668
    669                // Check connection.
    670                if (!connectionInterface.isOpen())
    671                        throw new InterfaceNotOpenException();
    672                // Check if device is remote.
    673                if (isRemote())
    674                        throw new OperationNotSupportedException("Cannot send data to a remote device from a remote device.");
    675
    676                logger.debug(toString() + "Sending data to {} >> {}.", address, HexUtils.prettyHexString(data));
    677
    678                XBeePacket xbeePacket;
    679                switch (getXBeeProtocol()) {
    680                case RAW_802_15_4:
    681                        xbeePacket = new TX64Packet(getNextFrameID(), address, XBeeTransmitOptions.NONE, data);
    682                        break;
    683                default:
    684                        xbeePacket = new TransmitPacket(getNextFrameID(), address, XBee16BitAddress.UNKNOWN_ADDRESS, 0, XBeeTransmitOptions.NONE, data);
    685                }
    686                sendAndCheckXBeePacket(xbeePacket, false);
    687        }
    688
    689        /**
    690         * Sends the provided data to the XBee device of the network corresponding
    691         * to the given 64-bit/16-bit address.
    692         *
    693         * <p>This method blocks till a success or error response arrives or the
    694         * configured receive timeout expires.</p>
    695         *
    696         * <p>The received timeout is configured using the {@code setReceiveTimeout}
    697         * method and can be consulted with {@code getReceiveTimeout} method.</p>
    698         *
    699         * <p>For non-blocking operations use the method
    700         * {@link #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[])}.</p>
    701         *
    702         * @param address64Bit The 64-bit address of the XBee that will receive the
    703         *                     data.
    704         * @param address16bit The 16-bit address of the XBee that will receive the
    705         *                     data. If it is unknown the
    706         *                     {@code XBee16BitAddress.UNKNOWN_ADDRESS} must be
    707         *                     used.
    708         * @param data Byte array containing the data to be sent.
    709         *
    710         * @throws InterfaceNotOpenException if this device connection is not open.
    711         * @throws NullPointerException if {@code address64Bit == null} or
    712         *                              if {@code address16bit == null} or
    713         *                              if {@code data == null}.
    714         * @throws TimeoutException if there is a timeout sending the data.
    715         * @throws XBeeException if a remote device is trying to send data or
    716         *                       if there is any other XBee related exception.
    717         *
    718         * @see #getReceiveTimeout()
    719         * @see #setReceiveTimeout(int)
    720         * @see #sendData(RemoteXBeeDevice, byte[])
    721         * @see #sendData(XBee64BitAddress, byte[])
    722         * @see #sendDataAsync(RemoteXBeeDevice, byte[])
    723         * @see #sendDataAsync(XBee64BitAddress, byte[])
    724         * @see #sendDataAsync(XBee64BitAddress, XBee16BitAddress, byte[])
    725         * @see com.digi.xbee.api.models.XBee16BitAddress
    726         * @see com.digi.xbee.api.models.XBee64BitAddress
    727         */
    728        protected void sendData(XBee64BitAddress address64Bit, XBee16BitAddress address16bit, byte[] data) throws TimeoutException, XBeeException {
    729                // Verify the parameters are not null, if they are null, throw an exception.
    730                if (address64Bit == null)
    731                        throw new NullPointerException("64-bit address cannot be null");
    732                if (address16bit == null)
    733                        throw new NullPointerException("16-bit address cannot be null");
    734                if (data == null)
    735                        throw new NullPointerException("Data cannot be null");
    736
    737                // Check connection.
    738                if (!connectionInterface.isOpen())
    739                        throw new InterfaceNotOpenException();
    740                // Check if device is remote.
    741                if (isRemote())
    742                        throw new OperationNotSupportedException("Cannot send data to a remote device from a remote device.");
    743
    744                logger.debug(toString() + "Sending data to {}[{}] >> {}.",
    745                                address64Bit, address16bit, HexUtils.prettyHexString(data));
    746
    747                XBeePacket xbeePacket = new TransmitPacket(getNextFrameID(), address64Bit, address16bit, 0, XBeeTransmitOptions.NONE, data);
    748                sendAndCheckXBeePacket(xbeePacket, false);
    749        }
    750
    751        /**
    752         * Sends the provided data to the given XBee device choosing the optimal
    753         * send method depending on the protocol of the local XBee device.
    754         *
    755         * <p>This method blocks till a success or error response arrives or the
    756         * configured receive timeout expires.</p>
    757         *
    758         * <p>The received timeout is configured using the {@code setReceiveTimeout}
    759         * method and can be consulted with {@code getReceiveTimeout} method.</p>
    760         *
    761         * <p>For non-blocking operations use the method
    762         * {@link #sendDataAsync(RemoteXBeeDevice, byte[])}.</p>
    763         *
    764         * @param xbeeDevice The XBee device of the network that will receive the
    765         *                   data.
    766         * @param data Byte array containing the data to be sent.
    767         *
    768         * @throws InterfaceNotOpenException if this device connection is not open.
    769         * @throws NullPointerException if {@code xbeeDevice == null} or
    770         *                              if {@code data == null}.
    771         * @throws TimeoutException if there is a timeout sending the data.
    772         * @throws XBeeException if there is any other XBee related exception.
    773         *
    774         * @see #getReceiveTimeout()
    775         * @see #setReceiveTimeout(int)
    776         * @see #sendDataAsync(RemoteXBeeDevice, byte[])
    777         */
    778        public void sendData(RemoteXBeeDevice xbeeDevice, byte[] data) throws TimeoutException, XBeeException {
    779                if (xbeeDevice == null)
    780                        throw new NullPointerException("Remote XBee device cannot be null");
    781
    782                switch (getXBeeProtocol()) {
    783                case ZIGBEE:
    784                case DIGI_POINT:
    785                        if (xbeeDevice.get64BitAddress() != null && xbeeDevice.get16BitAddress() != null)
    786                                sendData(xbeeDevice.get64BitAddress(), xbeeDevice.get16BitAddress(), data);
    787                        else
    788                                sendData(xbeeDevice.get64BitAddress(), data);
    789                        break;
    790                case RAW_802_15_4:
    791                        if (this instanceof Raw802Device) {
    792                                if (xbeeDevice.get64BitAddress() != null)
    793                                        ((Raw802Device)this).sendData(xbeeDevice.get64BitAddress(), data);
    794                                else
    795                                        ((Raw802Device)this).sendData(xbeeDevice.get16BitAddress(), data);
    796                        } else
    797                                sendData(xbeeDevice.get64BitAddress(), data);
    798                        break;
    799                case DIGI_MESH:
    800                default:
    801                        sendData(xbeeDevice.get64BitAddress(), data);
    802                }
    803        }
    804
    805        /**
    806         * Sends the provided data to all the XBee nodes of the network (broadcast).
    807         *
    808         * <p>This method blocks till a success or error transmit status arrives or
    809         * the configured receive timeout expires.</p>
    810         *
    811         * <p>The received timeout is configured using the {@code setReceiveTimeout}
    812         * method and can be consulted with {@code getReceiveTimeout} method.</p>
    813         *
    814         * @param data Byte array containing the data to be sent.
    815         *
    816         * @throws InterfaceNotOpenException if this device connection is not open.
    817         * @throws NullPointerException if {@code data == null}.
    818         * @throws TimeoutException if there is a timeout sending the data.
    819         * @throws XBeeException if there is any other XBee related exception.
    820         *
    821         * @see #getReceiveTimeout()
    822         * @see #setReceiveTimeout(int)
    823         */
    824        public void sendBroadcastData(byte[] data) throws TimeoutException, XBeeException {
    825                sendData(XBee64BitAddress.BROADCAST_ADDRESS, data);
    826        }
    827
    828        /**
    829         * Sends the given XBee packet and registers the given packet listener
    830         * (if not {@code null}) to be notified when the answers is received.
    831         *
    832         * <p>This is a non-blocking operation. To wait for the answer use
    833         * {@code sendPacket(XBeePacket)}.</p>
    834         *
    835         * @param packet XBee packet to be sent.
    836         * @param packetReceiveListener Listener for the operation, {@code null}
    837         *                              not to be notified when the answer arrives.
    838         *
    839         * @throws InterfaceNotOpenException if this device connection is not open.
    840         * @throws NullPointerException if {@code packet == null}.
    841         * @throws XBeeException if there is any other XBee related exception.
    842         *
    843         * @see #sendPacket(XBeePacket)
    844         * @see #sendPacketAsync(XBeePacket)
    845         * @see com.digi.xbee.api.listeners.IPacketReceiveListener
    846         * @see com.digi.xbee.api.packet.XBeePacket
    847         */
    848        public void sendPacket(XBeePacket packet, IPacketReceiveListener packetReceiveListener) throws XBeeException {
    849                try {
    850                        sendXBeePacket(packet, packetReceiveListener);
    851                } catch (IOException e) {
    852                        throw new XBeeException("Error writing in the communication interface.", e);
    853                }
    854        }
    855
    856        /**
    857         * Sends the given XBee packet asynchronously.
    858         *
    859         * <p>This is a non-blocking operation that do not wait for the answer and
    860         * is never notified when it arrives.</p>
    861         *
    862         * <p>To be notified when the answer is received, use
    863         * {@link #sendXBeePacket(XBeePacket, IPacketReceiveListener)}.</p>
    864         *
    865         * @param packet XBee packet to be sent asynchronously.
    866         *
    867         * @throws InterfaceNotOpenException if this device connection is not open.
    868         * @throws NullPointerException if {@code packet == null}.
    869         * @throws XBeeException if there is any other XBee related exception.
    870         *
    871         * @see #sendXBeePacket(XBeePacket)
    872         * @see #sendXBeePacket(XBeePacket, IPacketReceiveListener)
    873         * @see com.digi.xbee.api.packet.XBeePacket
    874         */
    875        public void sendPacketAsync(XBeePacket packet) throws XBeeException {
    876                try {
    877                        super.sendXBeePacket(packet, null);
    878                } catch (IOException e) {
    879                        throw new XBeeException("Error writing in the communication interface.", e);
    880                }
    881        }
    882
    883        /**
    884         * Sends the given XBee packet synchronously and blocks until the response
    885         * is received or the configured receive timeout expires.
    886         *
    887         * <p>The received timeout is configured using the {@code setReceiveTimeout}
    888         * method and can be consulted with {@code getReceiveTimeout} method.</p>
    889         *
    890         * <p>Use {@code sendXBeePacketAsync(XBeePacket)} or
    891         * {@code #sendXBeePacket(XBeePacket, IPacketReceiveListener)} for
    892         * non-blocking operations.</p>
    893         *
    894         * @param packet XBee packet to be sent.
    895         *
    896         * @return An {@code XBeePacket} object containing the response of the sent
    897         *         packet or {@code null} if there is no response.
    898         *
    899         * @throws InterfaceNotOpenException if this device connection is not open.
    900         * @throws NullPointerException if {@code packet == null}.
    901         * @throws TimeoutException if there is a timeout sending the XBee packet.
    902         * @throws XBeeException if there is any other XBee related exception.
    903         *
    904         * @see #getReceiveTimeout()
    905         * @see #sendXBeePacket(XBeePacket, IPacketReceiveListener)
    906         * @see #sendXBeePacketAsync(XBeePacket)
    907         * @see #setReceiveTimeout(int)
    908         * @see com.digi.xbee.api.packet.XBeePacket
    909         */
    910        public XBeePacket sendPacket(XBeePacket packet) throws TimeoutException, XBeeException {
    911                try {
    912                        return super.sendXBeePacket(packet);
    913                } catch (IOException e) {
    914                        throw new XBeeException("Error writing in the communication interface.", e);
    915                }
    916        }
    917
    918        /**
    919         * Waits until a Modem Status packet with a reset status,
    920         * {@code ModemStatusEvent.STATUS_HARDWARE_RESET} (0x00), or a watchdog
    921         * timer reset, {@code ModemStatusEvent.STATUS_WATCHDOG_TIMER_RESET} (0x01),
    922         * is received or the timeout expires.
    923         *
    924         * @return {@code true} if the Modem Status packet is received,
    925         *                      {@code false} otherwise.
    926         *
    927         * @see com.digi.xbee.api.models.ModemStatusEvent#STATUS_HARDWARE_RESET
    928         * @see com.digi.xbee.api.models.ModemStatusEvent#STATUS_WATCHDOG_TIMER_RESET
    929         */
    930        private boolean waitForModemResetStatusPacket() {
    931                modemStatusReceived = false;
    932                addModemStatusListener(resetStatusListener);
    933                synchronized (resetLock) {
    934                        try {
    935                                resetLock.wait(TIMEOUT_RESET);
    936                        } catch (InterruptedException e) { }
    937                }
    938                removeModemStatusListener(resetStatusListener);
    939                return modemStatusReceived;
    940        }
    941
    942        /**
    943         * Custom listener for modem reset packets.
    944         *
    945         * <p>When a Modem Status packet is received with status
    946         * {@code ModemStatusEvent.STATUS_HARDWARE_RESET} or
    947         * {@code ModemStatusEvent.STATUS_WATCHDOG_TIMER_RESET}, it
    948         * notifies the object that was waiting for the reception.</p>
    949         *
    950         * @see com.digi.xbee.api.listeners.IModemStatusReceiveListener
    951         * @see com.digi.xbee.api.models.ModemStatusEvent#STATUS_HARDWARE_RESET
    952         * @see com.digi.xbee.api.models.ModemStatusEvent#STATUS_WATCHDOG_TIMER_RESET
    953         */
    954        private IModemStatusReceiveListener resetStatusListener = new IModemStatusReceiveListener() {
    955
    956                /*
    957                 * (non-Javadoc)
    958                 * @see com.digi.xbee.api.listeners.IModemStatusReceiveListener#modemStatusEventReceived(com.digi.xbee.api.models.ModemStatusEvent)
    959                 */
    960                @Override
    961                public void modemStatusEventReceived(ModemStatusEvent modemStatusEvent) {
    962                        if (modemStatusEvent == ModemStatusEvent.STATUS_HARDWARE_RESET
    963                                        || modemStatusEvent == ModemStatusEvent.STATUS_WATCHDOG_TIMER_RESET){
    964                                modemStatusReceived = true;
    965                                // Continue execution by notifying the lock object.
    966                                synchronized (resetLock) {
    967                                        resetLock.notify();
    968                                }
    969                        }
    970                }
    971        };
    972
    973        /*
    974         * (non-Javadoc)
    975         * @see com.digi.xbee.api.AbstractXBeeDevice#reset()
    976         */
    977        @Override
    978        public void reset() throws TimeoutException, XBeeException {
    979                // Check connection.
    980                if (!connectionInterface.isOpen())
    981                        throw new InterfaceNotOpenException();
    982
    983                logger.info(toString() + "Resetting the local module...");
    984
    985                ATCommandResponse response = null;
    986                try {
    987                        response = sendATCommand(new ATCommand("FR"));
    988                } catch (IOException e) {
    989                        throw new XBeeException("Error writing in the communication interface.", e);
    990                }
    991
    992                // Check if AT Command response is valid.
    993                checkATCommandResponseIsValid(response);
    994
    995                // Wait for a Modem Status packet.
    996                if (!waitForModemResetStatusPacket())
    997                        throw new TimeoutException("Timeout waiting for the Modem Status packet.");
    998
    999                logger.info(toString() + "Module reset successfully.");
    1000        }
    1001
    1002        /**
    1003         * Reads new data received by this XBee device during the configured
    1004         * received timeout.
    1005         *
    1006         * <p>This method blocks until new data is received or the configured
    1007         * receive timeout expires.</p>
    1008         *
    1009         * <p>The received timeout is configured using the {@code setReceiveTimeout}
    1010         * method and can be consulted with {@code getReceiveTimeout} method.</p>
    1011         *
    1012         * <p>For non-blocking operations, register a {@code IDataReceiveListener}
    1013         * using the method {@link #addDataListener(IDataReceiveListener)}.</p>
    1014         *
    1015         * @return An {@code XBeeMessage} object containing the data and the source
    1016         *         address of the remote node that sent the data. {@code null} if
    1017         *         this did not receive new data during the configured receive
    1018         *         timeout.
    1019         *
    1020         * @throws InterfaceNotOpenException if this device connection is not open.
    1021         *
    1022         * @see #readData(int)
    1023         * @see #getReceiveTimeout()
    1024         * @see #setReceiveTimeout(int)
    1025         * @see #readDataFrom(RemoteXBeeDevice)
    1026         * @see #readDataFrom(RemoteXBeeDevice, int)
    1027         * @see com.digi.xbee.api.models.XBeeMessage
    1028         */
    1029        public XBeeMessage readData() {
    1030                return readDataPacket(null, TIMEOUT_READ_PACKET);
    1031        }
    1032
    1033        /**
    1034         * Reads new data received by this XBee device during the provided timeout.
    1035         *
    1036         * <p>This method blocks until new data is received or the provided timeout
    1037         * expires.</p>
    1038         *
    1039         * <p>For non-blocking operations, register a {@code IDataReceiveListener}
    1040         * using the method {@link #addDataListener(IDataReceiveListener)}.</p>
    1041         *
    1042         * @param timeout The time to wait for new data in milliseconds.
    1043         *
    1044         * @return An {@code XBeeMessage} object containing the data and the source
    1045         *         address of the remote node that sent the data. {@code null} if
    1046         *         this device did not receive new data during {@code timeout}
    1047         *         milliseconds.
    1048         *
    1049         * @throws IllegalArgumentException if {@code timeout < 0}.
    1050         * @throws InterfaceNotOpenException if this device connection is not open.
    1051         *
    1052         * @see #readData()
    1053         * @see #readDataFrom(RemoteXBeeDevice)
    1054         * @see #readDataFrom(RemoteXBeeDevice, int)
    1055         * @see com.digi.xbee.api.models.XBeeMessage
    1056         */
    1057        public XBeeMessage readData(int timeout) {
    1058                if (timeout < 0)
    1059                        throw new IllegalArgumentException("Read timeout must be 0 or greater.");
    1060
    1061                return readDataPacket(null, timeout);
    1062        }
    1063
    1064        /**
    1065         * Reads new data received from the given remote XBee device during the
    1066         * configured received timeout.
    1067         *
    1068         * <p>This method blocks until new data from the provided remote XBee
    1069         * device is received or the configured receive timeout expires.</p>
    1070         *
    1071         * <p>The received timeout is configured using the {@code setReceiveTimeout}
    1072         * method and can be consulted with {@code getReceiveTimeout} method.</p>
    1073         *
    1074         * <p>For non-blocking operations, register a {@code IDataReceiveListener}
    1075         * using the method {@link #addDataListener(IDataReceiveListener)}.</p>
    1076         *
    1077         * @param remoteXBeeDevice The remote device to read data from.
    1078         *
    1079         * @return An {@code XBeeMessage} object containing the data and the source
    1080         *         address of the remote node that sent the data. {@code null} if
    1081         *         this device did not receive new data from the provided remote
    1082         *         XBee device during the configured receive timeout.
    1083         *
    1084         * @throws InterfaceNotOpenException if this device connection is not open.
    1085         * @throws NullPointerException if {@code remoteXBeeDevice == null}.
    1086         *
    1087         * @see #readDataFrom(RemoteXBeeDevice, int)
    1088         * @see #getReceiveTimeout()
    1089         * @see #setReceiveTimeout(int)
    1090         * @see #readData()
    1091         * @see #readData(int)
    1092         * @see RemoteXBeeDevice
    1093         * @see com.digi.xbee.api.models.XBeeMessage
    1094         */
    1095        public XBeeMessage readDataFrom(RemoteXBeeDevice remoteXBeeDevice) {
    1096                if (remoteXBeeDevice == null)
    1097                        throw new NullPointerException("Remote XBee device cannot be null.");
    1098
    1099                return readDataPacket(remoteXBeeDevice, TIMEOUT_READ_PACKET);
    1100        }
    1101
    1102        /**
    1103         * Reads new data received from the given remote XBee device during the
    1104         * provided timeout.
    1105         *
    1106         * <p>This method blocks until new data from the provided remote XBee
    1107         * device is received or the given timeout expires.</p>
    1108         *
    1109         * <p>For non-blocking operations, register a {@code IDataReceiveListener}
    1110         * using the method {@link #addDataListener(IDataReceiveListener)}.</p>
    1111         *
    1112         * @param remoteXBeeDevice The remote device to read data from.
    1113         * @param timeout The time to wait for new data in milliseconds.
    1114         *
    1115         * @return An {@code XBeeMessage} object containing the data and the source
    1116         *         address of the remote node that sent the data. {@code null} if
    1117         *         this device did not receive new data from the provided remote
    1118         *         XBee device during {@code timeout} milliseconds.
    1119         *
    1120         * @throws IllegalArgumentException if {@code timeout < 0}.
    1121         * @throws InterfaceNotOpenException if this device connection is not open.
    1122         * @throws NullPointerException if {@code remoteXBeeDevice == null}.
    1123         *
    1124         * @see #readDataFrom(RemoteXBeeDevice)
    1125         * @see #getReceiveTimeout()
    1126         * @see #setReceiveTimeout(int)
    1127         * @see #readData()
    1128         * @see #readData(int)
    1129         * @see RemoteXBeeDevice
    1130         * @see com.digi.xbee.api.models.XBeeMessage
    1131         */
    1132        public XBeeMessage readDataFrom(RemoteXBeeDevice remoteXBeeDevice, int timeout) {
    1133                if (remoteXBeeDevice == null)
    1134                        throw new NullPointerException("Remote XBee device cannot be null.");
    1135                if (timeout < 0)
    1136                        throw new IllegalArgumentException("Read timeout must be 0 or greater.");
    1137
    1138                return readDataPacket(remoteXBeeDevice, timeout);
    1139        }
    1140
    1141        /**
    1142         * Reads a new data packet received by this XBee device during the provided
    1143         * timeout.
    1144         *
    1145         * <p>This method blocks until new data is received or the given timeout
    1146         * expires.</p>
    1147         *
    1148         * <p>If the provided remote XBee device is {@code null} the method returns
    1149         * the first data packet read from any remote device.
    1150         * <br>
    1151         * If it the remote device is not {@code null} the method returns the first
    1152         * data package read from the provided device.
    1153         * </p>
    1154         *
    1155         * @param remoteXBeeDevice The remote device to get a data packet from.
    1156         *                         {@code null} to read a data packet sent by any
    1157         *                         remote XBee device.
    1158         * @param timeout The time to wait for a data packet in milliseconds.
    1159         *
    1160         * @return An {@code XBeeMessage} received by this device, containing the
    1161         *         data and the source address of the remote node that sent the
    1162         *         data. {@code null} if this device did not receive new data
    1163         *         during {@code timeout} milliseconds.
    1164         *
    1165         * @throws InterfaceNotOpenException if this device connection is not open.
    1166         *
    1167         * @see RemoteXBeeDevice
    1168         * @see com.digi.xbee.api.models.XBeeMessage
    1169         */
    1170        private XBeeMessage readDataPacket(RemoteXBeeDevice remoteXBeeDevice, int timeout) {
    1171                // Check connection.
    1172                if (!connectionInterface.isOpen())
    1173                        throw new InterfaceNotOpenException();
    1174
    1175                XBeePacketsQueue xbeePacketsQueue = dataReader.getXBeePacketsQueue();
    1176                XBeePacket xbeePacket = null;
    1177
    1178                if (remoteXBeeDevice != null)
    1179                        xbeePacket = xbeePacketsQueue.getFirstDataPacketFrom(remoteXBeeDevice, timeout);
    1180                else
    1181                        xbeePacket = xbeePacketsQueue.getFirstDataPacket(timeout);
    1182
    1183                if (xbeePacket == null)
    1184                        return null;
    1185
    1186                // Obtain the source address and data from the packet.
    1187                RemoteXBeeDevice remoteDevice = null;
    1188                byte[] data = null;
    1189
    1190                APIFrameType packetType = ((XBeeAPIPacket)xbeePacket).getFrameType();
    1191                try {
    1192                        switch (packetType) {
    1193                        case RECEIVE_PACKET:
    1194                                ReceivePacket receivePacket = (ReceivePacket)xbeePacket;
    1195                                remoteDevice = getNetwork().getDevice(receivePacket.get64bitSourceAddress());
    1196                                if (remoteDevice == null) {
    1197                                        if (remoteXBeeDevice != null)
    1198                                                remoteDevice = remoteXBeeDevice;
    1199                                        else
    1200                                                remoteDevice = new RemoteXBeeDevice(this, receivePacket.get64bitSourceAddress());
    1201                                        getNetwork().addRemoteDevice(remoteDevice);
    1202                                }
    1203                                data = receivePacket.getRFData();
    1204                                break;
    1205                        case RX_16:
    1206                                RX16Packet rx16Packet = (RX16Packet)xbeePacket;
    1207                                remoteDevice = getNetwork().getDevice(rx16Packet.get16bitSourceAddress());
    1208                                if (remoteDevice == null) {
    1209                                        if (remoteXBeeDevice != null)
    1210                                                remoteDevice = remoteXBeeDevice;
    1211                                        else
    1212                                                remoteDevice = new RemoteRaw802Device(this, rx16Packet.get16bitSourceAddress());
    1213                                        getNetwork().addRemoteDevice(remoteDevice);
    1214                                }
    1215                                data = rx16Packet.getRFData();
    1216                                break;
    1217                        case RX_64:
    1218                                RX64Packet rx64Packet = (RX64Packet)xbeePacket;
    1219                                remoteDevice = getNetwork().getDevice(rx64Packet.get64bitSourceAddress());
    1220                                if (remoteDevice == null) {
    1221                                        if (remoteXBeeDevice != null)
    1222                                                remoteDevice = remoteXBeeDevice;
    1223                                        else
    1224                                                remoteDevice = new RemoteXBeeDevice(this, rx64Packet.get64bitSourceAddress());
    1225                                        getNetwork().addRemoteDevice(remoteDevice);
    1226                                }
    1227                                data = rx64Packet.getRFData();
    1228                                break;
    1229                        default:
    1230                                return null;
    1231                        }
    1232                } catch (XBeeException e) {
    1233                        logger.error(e.getMessage(), e);
    1234                }
    1235
    1236                // Create and return the XBee message.
    1237                return new XBeeMessage(remoteDevice, data, ((XBeeAPIPacket)xbeePacket).isBroadcast());
    1238        }
    1239
    1240        /*
    1241         * (non-Javadoc)
    1242         * @see com.digi.xbee.api.AbstractXBeeDevice#toString()
    1243         */
    1244        @Override
    1245        public String toString() {
    1246                String id = getNodeID() == null ? "" : getNodeID();
    1247                String addr64 = get64BitAddress() == null || get64BitAddress() == XBee64BitAddress.UNKNOWN_ADDRESS ?
    1248                                "" : get64BitAddress().toString();
    1249
    1250                if (id.length() == 0 && addr64.length() == 0)
    1251                        return super.toString();
    1252
    1253                StringBuilder message = new StringBuilder(super.toString());
    1254                message.append(addr64);
    1255                if (id.length() > 0) {
    1256                        message.append(" (");
    1257                        message.append(id);
    1258                        message.append(")");
    1259                }
    1260                message.append(" - ");
    1261
    1262                return message.toString();
    1263        }
    1264}