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                        return null;
1235                }
1236                
1237                // Create and return the XBee message.
1238                return new XBeeMessage(remoteDevice, data, ((XBeeAPIPacket)xbeePacket).isBroadcast());
1239        }
1240        
1241        /*
1242         * (non-Javadoc)
1243         * @see com.digi.xbee.api.AbstractXBeeDevice#toString()
1244         */
1245        @Override
1246        public String toString() {
1247                String id = getNodeID() == null ? "" : getNodeID();
1248                String addr64 = get64BitAddress() == null || get64BitAddress() == XBee64BitAddress.UNKNOWN_ADDRESS ? 
1249                                "" : get64BitAddress().toString();
1250                
1251                if (id.length() == 0 && addr64.length() == 0)
1252                        return super.toString();
1253                
1254                StringBuilder message = new StringBuilder(super.toString());
1255                message.append(addr64);
1256                if (id.length() > 0) {
1257                        message.append(" (");
1258                        message.append(id);
1259                        message.append(")");
1260                }
1261                message.append(" - ");
1262                
1263                return message.toString();
1264        }
1265}