001/**
002 * Copyright (c) 2014-2015 Digi International Inc.,
003 * All rights not expressly granted are reserved.
004 *
005 * This Source Code Form is subject to the terms of the Mozilla Public
006 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
007 * You can obtain one at http://mozilla.org/MPL/2.0/.
008 *
009 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
010 * =======================================================================
011 */
012package com.digi.xbee.api;
013
014import com.digi.xbee.api.connection.IConnectionInterface;
015import com.digi.xbee.api.connection.serial.SerialPortParameters;
016import com.digi.xbee.api.exceptions.InterfaceNotOpenException;
017import com.digi.xbee.api.exceptions.OperationNotSupportedException;
018import com.digi.xbee.api.exceptions.TimeoutException;
019import com.digi.xbee.api.exceptions.XBeeDeviceException;
020import com.digi.xbee.api.exceptions.XBeeException;
021import com.digi.xbee.api.listeners.IExplicitDataReceiveListener;
022import com.digi.xbee.api.models.APIOutputMode;
023import com.digi.xbee.api.models.AssociationIndicationStatus;
024import com.digi.xbee.api.models.ExplicitXBeeMessage;
025import com.digi.xbee.api.models.XBee16BitAddress;
026import com.digi.xbee.api.models.XBee64BitAddress;
027import com.digi.xbee.api.models.XBeeProtocol;
028import com.digi.xbee.api.models.XBeeTransmitOptions;
029import com.digi.xbee.api.packet.XBeePacket;
030import com.digi.xbee.api.packet.common.ExplicitAddressingPacket;
031import com.digi.xbee.api.utils.HexUtils;
032
033/**
034 * This class represents a local ZigBee device.
035 * 
036 * @see XBeeDevice
037 * @see DigiMeshDevice
038 * @see DigiPointDevice
039 * @see Raw802Device
040 */
041public class ZigBeeDevice extends XBeeDevice {
042
043        /**
044         * Class constructor. Instantiates a new {@code ZigBeeDevice} object in the 
045         * given port name and baud rate.
046         * 
047         * @param port Serial port name where ZigBee device is attached to.
048         * @param baudRate Serial port baud rate to communicate with the device. 
049         *                 Other connection parameters will be set as default (8 
050         *                 data bits, 1 stop bit, no parity, no flow control).
051         * 
052         * @throws IllegalArgumentException if {@code baudRate < 0}.
053         * @throws NullPointerException if {@code port == null}.
054         */
055        public ZigBeeDevice(String port, int baudRate) {
056                this(XBee.createConnectiontionInterface(port, baudRate));
057        }
058        
059        /**
060         * Class constructor. Instantiates a new {@code ZigBeeDevice} object in the 
061         * given serial port name and settings.
062         * 
063         * @param port Serial port name where ZigBee device is attached to.
064         * @param baudRate Serial port baud rate to communicate with the device.
065         * @param dataBits Serial port data bits.
066         * @param stopBits Serial port data bits.
067         * @param parity Serial port data bits.
068         * @param flowControl Serial port data bits.
069         * 
070         * @throws IllegalArgumentException if {@code baudRate < 0} or
071         *                                  if {@code dataBits < 0} or
072         *                                  if {@code stopBits < 0} or
073         *                                  if {@code parity < 0} or
074         *                                  if {@code flowControl < 0}.
075         * @throws NullPointerException if {@code port == null}.
076         */
077        public ZigBeeDevice(String port, int baudRate, int dataBits, int stopBits, int parity, int flowControl) {
078                this(port, new SerialPortParameters(baudRate, dataBits, stopBits, parity, flowControl));
079        }
080        
081        /**
082         * Class constructor. Instantiates a new {@code ZigBeeDevice} object in the 
083         * given serial port name and parameters.
084         * 
085         * @param port Serial port name where ZigBee device is attached to.
086         * @param serialPortParameters Object containing the serial port parameters.
087         * 
088         * @throws NullPointerException if {@code port == null} or
089         *                              if {@code serialPortParameters == null}.
090         * 
091         * @see com.digi.xbee.api.connection.serial.SerialPortParameters
092         */
093        public ZigBeeDevice(String port, SerialPortParameters serialPortParameters) {
094                this(XBee.createConnectiontionInterface(port, serialPortParameters));
095        }
096        
097        /**
098         * Class constructor. Instantiates a new {@code ZigBeeDevice} object with the 
099         * given connection interface.
100         * 
101         * @param connectionInterface The connection interface with the physical 
102         *                            ZigBee device.
103         * 
104         * @throws NullPointerException if {@code connectionInterface == null}
105         * 
106         * @see com.digi.xbee.api.connection.IConnectionInterface
107         */
108        public ZigBeeDevice(IConnectionInterface connectionInterface) {
109                super(connectionInterface);
110        }
111        
112        /*
113         * (non-Javadoc)
114         * @see com.digi.xbee.api.XBeeDevice#open()
115         */
116        @Override
117        public void open() throws XBeeException {
118                super.open();
119                if (xbeeProtocol != XBeeProtocol.ZIGBEE)
120                        throw new XBeeDeviceException("XBee device is not a " + getXBeeProtocol().getDescription() + " device, it is a " + xbeeProtocol.getDescription() + " device.");
121        }
122        
123        /*
124         * (non-Javadoc)
125         * @see com.digi.xbee.api.XBeeDevice#getNetwork()
126         */
127        @Override
128        public XBeeNetwork getNetwork() {
129                if (!isOpen())
130                        throw new InterfaceNotOpenException();
131                if (network == null)
132                        network = new ZigBeeNetwork(this);
133                return network;
134        }
135        
136        /*
137         * (non-Javadoc)
138         * @see com.digi.xbee.api.XBeeDevice#getXBeeProtocol()
139         */
140        @Override
141        public XBeeProtocol getXBeeProtocol() {
142                return XBeeProtocol.ZIGBEE;
143        }
144        
145        /*
146         * (non-Javadoc)
147         * @see com.digi.xbee.api.XBeeDevice#sendDataAsync(com.digi.xbee.api.models.XBee64BitAddress, com.digi.xbee.api.models.XBee16BitAddress, byte[])
148         */
149        @Override
150        public void sendDataAsync(XBee64BitAddress address64Bit, XBee16BitAddress address16bit, byte[] data) throws XBeeException {
151                super.sendDataAsync(address64Bit, address16bit, data);
152        }
153        
154        /*
155         * (non-Javadoc)
156         * @see com.digi.xbee.api.XBeeDevice#sendData(com.digi.xbee.api.models.XBee64BitAddress, com.digi.xbee.api.models.XBee16BitAddress, byte[])
157         */
158        @Override
159        public void sendData(XBee64BitAddress address64Bit, XBee16BitAddress address16bit, byte[] data) throws TimeoutException, XBeeException {
160                super.sendData(address64Bit, address16bit, data);
161        }
162        
163        /*
164         * (non-Javadoc)
165         * @see com.digi.xbee.api.AbstractXBeeDevice#getAssociationIndicationStatus()
166         */
167        @Override
168        public AssociationIndicationStatus getAssociationIndicationStatus() throws TimeoutException, XBeeException {
169                return super.getAssociationIndicationStatus();
170        }
171        
172        /*
173         * (non-Javadoc)
174         * @see com.digi.xbee.api.AbstractXBeeDevice#forceDisassociate()
175         */
176        @Override
177        public void forceDisassociate() throws TimeoutException, XBeeException {
178                super.forceDisassociate();
179        }
180        
181        /*
182         * (non-Javadoc)
183         * @see com.digi.xbee.api.XBeeDevice#readExplicitData()
184         */
185        @Override
186        public ExplicitXBeeMessage readExplicitData() {
187                return super.readExplicitData();
188        }
189        
190        /*
191         * (non-Javadoc)
192         * @see com.digi.xbee.api.XBeeDevice#readExplicitData(int)
193         */
194        @Override
195        public ExplicitXBeeMessage readExplicitData(int timeout) {
196                return super.readExplicitData(timeout);
197        }
198        
199        /*
200         * (non-Javadoc)
201         * @see com.digi.xbee.api.XBeeDevice#readExplicitDataFrom(com.digi.xbee.api.RemoteXBeeDevice)
202         */
203        @Override
204        public ExplicitXBeeMessage readExplicitDataFrom(RemoteXBeeDevice remoteXBeeDevice) {
205                return super.readExplicitDataFrom(remoteXBeeDevice);
206        }
207        
208        /*
209         * (non-Javadoc)
210         * @see com.digi.xbee.api.XBeeDevice#readExplicitDataFrom(com.digi.xbee.api.RemoteXBeeDevice, int)
211         */
212        @Override
213        public ExplicitXBeeMessage readExplicitDataFrom(RemoteXBeeDevice remoteXBeeDevice, int timeout) {
214                return super.readExplicitDataFrom(remoteXBeeDevice, timeout);
215        }
216        
217        /*
218         * (non-Javadoc)
219         * @see com.digi.xbee.api.AbstractXBeeDevice#addExplicitDataListener(com.digi.xbee.api.listeners.IExplicitDataReceiveListener)
220         */
221        @Override
222        public void addExplicitDataListener(IExplicitDataReceiveListener listener) {
223                super.addExplicitDataListener(listener);
224        }
225        
226        /*
227         * (non-Javadoc)
228         * @see com.digi.xbee.api.AbstractXBeeDevice#removeExplicitDataListener(com.digi.xbee.api.listeners.IExplicitDataReceiveListener)
229         */
230        @Override
231        public void removeExplicitDataListener(IExplicitDataReceiveListener listener) {
232                super.removeExplicitDataListener(listener);
233        }
234        
235        /*
236         * (non-Javadoc)
237         * @see com.digi.xbee.api.XBeeDevice#getAPIOutputMode()
238         */
239        @Override
240        public APIOutputMode getAPIOutputMode() throws TimeoutException, XBeeException {
241                return super.getAPIOutputMode();
242        }
243        
244        /*
245         * (non-Javadoc)
246         * @see com.digi.xbee.api.XBeeDevice#setAPIOutputMode(com.digi.xbee.api.models.APIOutputMode)
247         */
248        @Override
249        public void setAPIOutputMode(APIOutputMode apiOutputMode) throws TimeoutException, XBeeException {
250                super.setAPIOutputMode(apiOutputMode);
251        }
252        
253        /*
254         * (non-Javadoc)
255         * @see com.digi.xbee.api.XBeeDevice#sendExplicitData(com.digi.xbee.api.RemoteXBeeDevice, int, int, int, int, byte[])
256         */
257        @Override
258        public void sendExplicitData(RemoteXBeeDevice remoteXBeeDevice, int sourceEndpoint, int destEndpoint, int clusterID,
259                        int profileID, byte[] data) throws TimeoutException, XBeeException {
260                super.sendExplicitData(remoteXBeeDevice, sourceEndpoint, destEndpoint, clusterID, profileID, data);
261        }
262        
263        /*
264         * (non-Javadoc)
265         * @see com.digi.xbee.api.XBeeDevice#sendExplicitData(com.digi.xbee.api.models.XBee64BitAddress, com.digi.xbee.api.models.XBee16BitAddress, int, int, int, int, byte[])
266         */
267        @Override
268        public void sendExplicitData(XBee64BitAddress address64Bit, XBee16BitAddress address16bit, int sourceEndpoint, int destEndpoint, 
269                        int clusterID, int profileID, byte[] data) throws TimeoutException, XBeeException {
270                super.sendExplicitData(address64Bit, address16bit, sourceEndpoint, destEndpoint, clusterID, profileID, data);
271        }
272        
273        /*
274         * (non-Javadoc)
275         * @see com.digi.xbee.api.XBeeDevice#sendBroadcastExplicitData(int, int, int, int, byte[])
276         */
277        @Override
278        public void sendBroadcastExplicitData(int sourceEndpoint, int destEndpoint, int clusterID, int profileID, 
279                        byte[] data) throws TimeoutException, XBeeException {
280                super.sendBroadcastExplicitData(sourceEndpoint, destEndpoint, clusterID, profileID, data);
281        }
282        
283        /*
284         * (non-Javadoc)
285         * @see com.digi.xbee.api.XBeeDevice#sendExplicitDataAsync(com.digi.xbee.api.RemoteXBeeDevice, int, int, int, int, byte[])
286         */
287        @Override
288        public void sendExplicitDataAsync(RemoteXBeeDevice xbeeDevice, int sourceEndpoint, int destEndpoint, int clusterID,
289                        int profileID, byte[] data) throws XBeeException {
290                super.sendExplicitDataAsync(xbeeDevice, sourceEndpoint, destEndpoint, clusterID, profileID, data);
291        }
292        
293        /*
294         * (non-Javadoc)
295         * @see com.digi.xbee.api.XBeeDevice#sendExplicitDataAsync(com.digi.xbee.api.models.XBee64BitAddress, com.digi.xbee.api.models.XBee16BitAddress, int, int, int, int, byte[])
296         */
297        @Override
298        public void sendExplicitDataAsync(XBee64BitAddress address64Bit, XBee16BitAddress address16Bit, int sourceEndpoint,
299                        int destEndpoint, int clusterID, int profileID, byte[] data) throws XBeeException {
300                super.sendExplicitDataAsync(address64Bit, address16Bit, sourceEndpoint, destEndpoint, clusterID, profileID, data);
301        }
302        
303        /**
304         * Sends a multicast transmission with the provided data to the given 
305         * group ID.
306         * 
307         * <p>This method blocks till a success or error response arrives or the 
308         * configured receive timeout expires.</p>
309         * 
310         * <p>The receive timeout is configured using the setReceiveTimeout method 
311         * and can be consulted with getReceiveTimeout method.</p>
312         * 
313         * @param groupID 16-bit address of the destination group ID.
314         * @param sourceEndpoint Source endpoint for the transmission.
315         * @param destEndpoint Destination endpoint for the transmission.
316         * @param clusterID Cluster ID used in the transmission.
317         * @param profileID Profile ID used in the transmission.
318         * @param data Byte array containing the data to be sent.
319         * 
320         * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 
321         *                                  if {@code sourceEndpoint > 0xFF} or 
322         *                                  if {@code destEndpoint < 0} or 
323         *                                  if {@code destEndpoint > 0xFF} or 
324         *                                  if {@code clusterID < 0} or 
325         *                                  if {@code clusterID > 0xFFFF} or 
326         *                                  if {@code profileID < 0} or 
327         *                                  if {@code profileID > 0xFFFF}.
328         * @throws InterfaceNotOpenException if this device connection is not open.
329         * @throws NullPointerException if {@code groupID == null} or 
330         *                              if {@code data == null}.
331         * @throws TimeoutException if there is a timeout sending the data.
332         * @throws XBeeException if there is any other XBee related exception.
333         * 
334         * @see #sendMulticastDataAsync(XBee16BitAddress, int, int, int, int, byte[])
335         * @see #getReceiveTimeout()
336         * @see #setReceiveTimeout(int)
337         * @see com.digi.xbee.api.models.XBee16BitAddress
338         */
339        public void sendMulticastData(XBee16BitAddress groupID, int sourceEndpoint, int destEndpoint, int clusterID,
340                        int profileID, byte[] data) throws XBeeException {
341                // Verify the parameters are not null, if they are null, throw an exception.
342                if (groupID == null)
343                        throw new NullPointerException("Destination group ID cannot be null");
344                if (data == null)
345                        throw new NullPointerException("Data cannot be null.");
346                if (sourceEndpoint < 0 || sourceEndpoint > 0xFF)
347                        throw new IllegalArgumentException("Source endpoint must be between 0 and 0xFF.");
348                if (destEndpoint < 0 || destEndpoint > 0xFF)
349                        throw new IllegalArgumentException("Destination endpoint must be between 0 and 0xFF.");
350                if (clusterID < 0 || clusterID > 0xFFFF)
351                        throw new IllegalArgumentException("Cluster ID must be between 0 and 0xFFFF.");
352                if (profileID < 0 || profileID > 0xFFFF)
353                        throw new IllegalArgumentException("Profile ID must be between 0 and 0xFFFF.");
354                
355                // Check if device is remote.
356                if (isRemote())
357                        throw new OperationNotSupportedException("Cannot send multicast data to a remote device from a remote device.");
358                
359                logger.debug(toString() + "Sending multicast data to {} [{} - {} - {} - {}] >> {}.", groupID, 
360                                HexUtils.integerToHexString(sourceEndpoint, 1), HexUtils.integerToHexString(destEndpoint, 1), 
361                                HexUtils.integerToHexString(clusterID, 2), HexUtils.integerToHexString(profileID, 2), 
362                                HexUtils.prettyHexString(data));
363                
364                XBeePacket xbeePacket = new ExplicitAddressingPacket(getNextFrameID(), XBee64BitAddress.UNKNOWN_ADDRESS, 
365                                groupID, sourceEndpoint, destEndpoint, clusterID, profileID, 0, XBeeTransmitOptions.ENABLE_MULTICAST, data);
366                sendAndCheckXBeePacket(xbeePacket, false);
367        }
368        
369        /**
370         * Sends a multicast asynchronous transmission with the provided data to 
371         * the given group ID.
372         * 
373         * <p>Asynchronous transmissions do not wait for answer from the remote 
374         * device or for transmit status packet.</p>
375         * 
376         * @param groupID 16-bit address of the destination group ID.
377         * @param sourceEndpoint Source endpoint for the transmission.
378         * @param destEndpoint Destination endpoint for the transmission.
379         * @param clusterID Cluster ID used in the transmission.
380         * @param profileID Profile ID used in the transmission.
381         * @param data Byte array containing the data to be sent.
382         * 
383         * @throws IllegalArgumentException if {@code sourceEndpoint < 0} or 
384         *                                  if {@code sourceEndpoint > 0xFF} or 
385         *                                  if {@code destEndpoint < 0} or 
386         *                                  if {@code destEndpoint > 0xFF} or 
387         *                                  if {@code clusterID < 0} or 
388         *                                  if {@code clusterID > 0xFFFF} or 
389         *                                  if {@code profileID < 0} or 
390         *                                  if {@code profileID > 0xFFFF}.
391         * @throws InterfaceNotOpenException if this device connection is not open.
392         * @throws NullPointerException if {@code groupID == null} or 
393         *                              if {@code data == null}.
394         * @throws XBeeException if there is any other XBee related exception.
395         * 
396         * @see #sendMulticastData(XBee16BitAddress, int, int, int, int, byte[])
397         * @see com.digi.xbee.api.models.XBee64BitAddress
398         */
399        public void sendMulticastDataAsync(XBee16BitAddress groupID, int sourceEndpoint, int destEndpoint, int clusterID,
400                        int profileID, byte[] data) throws XBeeException {
401                // Verify the parameters are not null, if they are null, throw an exception.
402                if (groupID == null)
403                        throw new NullPointerException("Destination group ID cannot be null");
404                if (data == null)
405                        throw new NullPointerException("Data cannot be null.");
406                if (sourceEndpoint < 0 || sourceEndpoint > 0xFF)
407                        throw new IllegalArgumentException("Source endpoint must be between 0 and 0xFF.");
408                if (destEndpoint < 0 || destEndpoint > 0xFF)
409                        throw new IllegalArgumentException("Destination endpoint must be between 0 and 0xFF.");
410                if (clusterID < 0 || clusterID > 0xFFFF)
411                        throw new IllegalArgumentException("Cluster ID must be between 0 and 0xFFFF.");
412                if (profileID < 0 || profileID > 0xFFFF)
413                        throw new IllegalArgumentException("Profile ID must be between 0 and 0xFFFF.");
414                
415                // Check if device is remote.
416                if (isRemote())
417                        throw new OperationNotSupportedException("Cannot send multicast data to a remote device from a remote device.");
418                
419                logger.debug(toString() + "Sending multicast data asynchronously to {} [{} - {} - {} - {}] >> {}.", groupID, 
420                                HexUtils.integerToHexString(sourceEndpoint, 1), HexUtils.integerToHexString(destEndpoint, 1), 
421                                HexUtils.integerToHexString(clusterID, 2), HexUtils.integerToHexString(profileID, 2), 
422                                HexUtils.prettyHexString(data));
423                
424                XBeePacket xbeePacket = new ExplicitAddressingPacket(getNextFrameID(), XBee64BitAddress.UNKNOWN_ADDRESS, 
425                                groupID, sourceEndpoint, destEndpoint, clusterID, profileID, 0, XBeeTransmitOptions.ENABLE_MULTICAST, data);
426                sendAndCheckXBeePacket(xbeePacket, true);
427        }
428}