001/*
002 * Copyright 2017-2019, Digi International Inc.
003 *
004 * This Source Code Form is subject to the terms of the Mozilla Public
005 * License, v. 2.0. If a copy of the MPL was not distributed with this
006 * file, you can obtain one at http://mozilla.org/MPL/2.0/.
007 *
008 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 
009 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 
010 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 
011 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
012 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
013 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
014 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
015 */
016package com.digi.xbee.api;
017
018import java.net.Inet6Address;
019
020import com.digi.xbee.api.connection.IConnectionInterface;
021import com.digi.xbee.api.connection.serial.SerialPortParameters;
022import com.digi.xbee.api.exceptions.InterfaceNotOpenException;
023import com.digi.xbee.api.exceptions.OperationNotSupportedException;
024import com.digi.xbee.api.exceptions.TimeoutException;
025import com.digi.xbee.api.exceptions.XBeeDeviceException;
026import com.digi.xbee.api.exceptions.XBeeException;
027import com.digi.xbee.api.models.AssociationIndicationStatus;
028import com.digi.xbee.api.models.CoAPURI;
029import com.digi.xbee.api.models.HTTPMethodEnum;
030import com.digi.xbee.api.models.IPProtocol;
031import com.digi.xbee.api.models.RemoteATCommandOptions;
032import com.digi.xbee.api.models.ThreadAssociationIndicationStatus;
033import com.digi.xbee.api.models.XBeeProtocol;
034import com.digi.xbee.api.packet.thread.CoAPTxRequestPacket;
035import com.digi.xbee.api.utils.ByteUtils;
036import com.digi.xbee.api.utils.HexUtils;
037
038/**
039 * This class represents a local Thread device.
040 * 
041 * @see CellularDevice
042 * @see DigiPointDevice
043 * @see DigiMeshDevice
044 * @see Raw802Device
045 * @see WiFiDevice
046 * @see XBeeDevice
047 * @see ZigBeeDevice
048 * 
049 * @since 1.2.1
050 */
051public class ThreadDevice extends IPv6Device {
052
053        // Constants
054        private static final String OPERATION_EXCEPTION = "Operation not supported in Thread protocol.";
055        
056        private static final String ERROR_PROTOCOL_ILLEGAL = String.format("Protocol must be %s or %s.", 
057                        IPProtocol.UDP.getName(), IPProtocol.COAP.getName());
058        
059        /**
060         * Class constructor. Instantiates a new {@code ThreadDevice} object in 
061         * the given port name and baud rate.
062         * 
063         * @param port Serial port name where Thread device is attached to.
064         * @param baudRate Serial port baud rate to communicate with the device. 
065         *                 Other connection parameters will be set as default (8 
066         *                 data bits, 1 stop bit, no parity, no flow control).
067         * 
068         * @throws IllegalArgumentException if {@code baudRate < 0}.
069         * @throws NullPointerException if {@code port == null}.
070         * 
071         * @see #ThreadDevice(IConnectionInterface)
072         * @see #ThreadDevice(String, SerialPortParameters)
073         * @see #ThreadDevice(String, int, int, int, int, int)
074         */
075        public ThreadDevice(String port, int baudRate) {
076                this(XBee.createConnectiontionInterface(port, baudRate));
077        }
078        
079        /**
080         * Class constructor. Instantiates a new {@code ThreadDevice} object in 
081         * the given serial port name and settings.
082         * 
083         * @param port Serial port name where Thread device is attached to.
084         * @param baudRate Serial port baud rate to communicate with the device.
085         * @param dataBits Serial port data bits.
086         * @param stopBits Serial port data bits.
087         * @param parity Serial port data bits.
088         * @param flowControl Serial port data bits.
089         * 
090         * @throws IllegalArgumentException if {@code baudRate < 0} or
091         *                                  if {@code dataBits < 0} or
092         *                                  if {@code stopBits < 0} or
093         *                                  if {@code parity < 0} or
094         *                                  if {@code flowControl < 0}.
095         * @throws NullPointerException if {@code port == null}.
096         * 
097         * @see #ThreadDevice(IConnectionInterface)
098         * @see #ThreadDevice(String, int)
099         * @see #ThreadDevice(String, SerialPortParameters)
100         */
101        public ThreadDevice(String port, int baudRate, int dataBits, int stopBits, int parity, int flowControl) {
102                this(port, new SerialPortParameters(baudRate, dataBits, stopBits, parity, flowControl));
103        }
104        
105        /**
106         * Class constructor. Instantiates a new {@code ThreadDevice} object in 
107         * the given serial port name and parameters.
108         * 
109         * @param port Serial port name where Thread device is attached to.
110         * @param serialPortParameters Object containing the serial port parameters.
111         * 
112         * @throws NullPointerException if {@code port == null} or
113         *                              if {@code serialPortParameters == null}.
114         * 
115         * @see #ThreadDevice(IConnectionInterface)
116         * @see #ThreadDevice(String, int)
117         * @see #ThreadDevice(String, int, int, int, int, int)
118         * @see com.digi.xbee.api.connection.serial.SerialPortParameters
119         */
120        public ThreadDevice(String port, SerialPortParameters serialPortParameters) {
121                this(XBee.createConnectiontionInterface(port, serialPortParameters));
122        }
123        
124        /**
125         * Class constructor. Instantiates a new {@code ThreadDevice} object with 
126         * the given connection interface.
127         * 
128         * @param connectionInterface The connection interface with the physical 
129         *                            Thread device.
130         * 
131         * @throws NullPointerException if {@code connectionInterface == null}
132         * 
133         * @see #ThreadDevice(String, int)
134         * @see #ThreadDevice(String, SerialPortParameters)
135         * @see #ThreadDevice(String, int, int, int, int, int)
136         * @see com.digi.xbee.api.connection.IConnectionInterface
137         */
138        public ThreadDevice(IConnectionInterface connectionInterface) {
139                super(connectionInterface);
140        }
141        
142        /*
143         * (non-Javadoc)
144         * @see com.digi.xbee.api.XBeeDevice#open()
145         */
146        @Override
147        public void open() throws XBeeException {
148                super.open();
149                if (xbeeProtocol != XBeeProtocol.THREAD)
150                        throw new XBeeDeviceException("XBee device is not a " + getXBeeProtocol().getDescription() +
151                                        " device, it is a " + xbeeProtocol.getDescription() + " device.");
152        }
153        
154        /*
155         * (non-Javadoc)
156         * @see com.digi.xbee.api.XBeeDevice#getXBeeProtocol()
157         */
158        @Override
159        public XBeeProtocol getXBeeProtocol() {
160                return XBeeProtocol.THREAD;
161        }
162        
163        /**
164         * Returns whether the device is associated to a network or not.
165         * 
166         * @return {@code true} if the device is connected to a network, 
167         *         {@code false} otherwise.
168         * 
169         * @throws InterfaceNotOpenException if this device connection is not open.
170         * @throws TimeoutException if there is a timeout getting the association 
171         *                          indication status.
172         * @throws XBeeException if there is any other XBee related exception.
173         * 
174         * @see #getThreadAssociationIndicationStatus()
175         * @see com.digi.xbee.api.models.ThreadAssociationIndicationStatus
176         */
177        public boolean isConnected() throws TimeoutException, XBeeException {
178                ThreadAssociationIndicationStatus status = getThreadAssociationIndicationStatus();
179                return status == ThreadAssociationIndicationStatus.ASSOCIATED;
180        }
181        
182        /**
183         * Returns the current association status of this Thread device.
184         * 
185         * @return The association indication status of the Thread device.
186         * 
187         * @throws InterfaceNotOpenException if this device connection is not open.
188         * @throws TimeoutException if there is a timeout getting the association 
189         *                          indication status.
190         * @throws XBeeException if there is any other XBee related exception.
191         * 
192         * @see com.digi.xbee.api.models.ThreadAssociationIndicationStatus
193         */
194        public ThreadAssociationIndicationStatus getThreadAssociationIndicationStatus() throws TimeoutException, 
195                        XBeeException {
196                byte[] associationIndicationValue = getParameter("AI");
197                return ThreadAssociationIndicationStatus.get(ByteUtils.byteArrayToInt(associationIndicationValue));
198        }
199        
200        /**
201         * @deprecated Operation not supported in Thread protocol. This method
202         *             will raise an {@link UnsupportedOperationException}.
203         */
204        @Override
205        protected AssociationIndicationStatus getAssociationIndicationStatus()
206                        throws TimeoutException, XBeeException {
207                // Not supported in Thread.
208                throw new UnsupportedOperationException(OPERATION_EXCEPTION);
209        }
210        
211        /**
212         * Sends the provided CoAP IPv6 data to the given IPv6 address and port using 
213         * the specified IPv6 protocol.
214         * 
215         * <p>This method blocks till a success or error response arrives or the 
216         * configured receive timeout expires.</p>
217         * 
218         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
219         * method and can be consulted with {@code getReceiveTimeout} method.</p>
220         * 
221         * <p>For non-blocking operations use the method 
222         * {@link #sendCoAPDataAsync(Inet6Address, String, HTTPMethodEnum, byte[])}.</p>
223         * 
224         * @param ipv6Address The IPv6 address to send CoAP IPv6 data to.
225         * @param uri Uniform Resource Identifier. Every CoAP message must have a 
226         *            valid URI string and must meet the following criteria. There 
227         *            are built-in CoAP URIs:
228         *            <ul>
229         *              <li><b>CoAPURI.URI_DATA_TRANSMISSION:</b> "XB/TX" 
230         *              for data transmissions (HTTP method must be set to PUT)</li>
231         *              <li><b>CoAPURI.URI_AT_COMMAND:</b> "XB/AT" for 
232         *              AT Command operation (HTTP method must be set to PUT or GET). 
233         *              After the URI, an AT command needs to be specified, for example: 
234         *              CoAPURI.URI_AT_COMMAND + "/NI"</li>
235         *              <li><b>CoAPURI.URI_IO_SAMPLING:</b> "XB/IO" for 
236         *              IO operation (HTTP method must be set to POST)</li>
237         *            </ul>
238         * @param method HTTP method used for the transmission.
239         * @param data Byte array containing the CoAP IPv6 data to be sent.
240         * 
241         * @return A byte array containing the response, if any. Otherwise, {@code null}.
242         * 
243         * @throws IllegalArgumentException if {@code uri} starts with "XB/AT" and 
244         *                                  its length is lesser than 8 (XB/AT/XX).
245         * @throws InterfaceNotOpenException if this device connection is not open.
246         * @throws NullPointerException if {@code ipv6Address == null} or 
247         *                              if {@code uri == null} or 
248         *                              if {@code method == null}.
249         * @throws TimeoutException if there is a timeout sending the data.
250         * @throws XBeeException if there is any other XBee related exception.
251         * 
252         * @see #getReceiveTimeout()
253         * @see #sendCoAPData(Inet6Address, String, HTTPMethodEnum, boolean, byte[])
254         * @see #sendCoAPDataAsync(Inet6Address, String, HTTPMethodEnum, byte[])
255         * @see #sendCoAPDataAsync(Inet6Address, String, HTTPMethodEnum, boolean, byte[])
256         * @see #setReceiveTimeout(int)
257         * @see com.digi.xbee.api.models.HTTPMethodEnum
258         * @see java.net.Inet6Address
259         */
260        public byte[] sendCoAPData(Inet6Address ipv6Address, String uri,
261                        HTTPMethodEnum method, byte[] data) throws TimeoutException, IllegalArgumentException, XBeeException {
262                boolean applyChanges = uri.startsWith(CoAPURI.URI_AT_COMMAND);
263                return sendCoAPData(ipv6Address, uri, method, applyChanges, data, false);
264        }
265        
266        /**
267         * Sends the provided CoAP IPv6 data to the given IPv6 address and port using 
268         * the specified IPv6 protocol.
269         * 
270         * <p>This method blocks till a success or error response arrives or the 
271         * configured receive timeout expires.</p>
272         * 
273         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
274         * method and can be consulted with {@code getReceiveTimeout} method.</p>
275         * 
276         * <p>For non-blocking operations use the method 
277         * {@link #sendCoAPDataAsync(Inet6Address, String, HTTPMethodEnum, 
278         * boolean, byte[])}.</p>
279         * 
280         * @param ipv6Address The IPv6 address to send CoAP IPv6 data to.
281         * @param uri Uniform Resource Identifier. Every CoAP message must have a 
282         *            valid URI string and must meet the following criteria. There 
283         *            are built-in CoAP URIs:
284         *            <ul>
285         *              <li><b>CoAPURI.URI_DATA_TRANSMISSION:</b> "XB/TX" 
286         *              for data transmissions (HTTP method must be set to PUT)</li>
287         *              <li><b>CoAPURI.URI_AT_COMMAND:</b> "XB/AT" for 
288         *              AT Command operation (HTTP method must be set to PUT or GET). 
289         *              After the URI, an AT command needs to be specified, for example: 
290         *              CoAPURI.URI_AT_COMMAND + "/NI"</li>
291         *              <li><b>CoAPURI.URI_IO_SAMPLING:</b> "XB/IO" for 
292         *              IO operation (HTTP method must be set to POST)</li>
293         *            </ul>
294         * @param method HTTP method used for the transmission.
295         * @param applyChanges {@code true} to apply the changes after sending the 
296         *                     packet, {@code false} otherwise.
297         * @param data Byte array containing the CoAP IPv6 data to be sent.
298         * 
299         * @return A byte array containing the response, if any. Otherwise, {@code null}.
300         * 
301         * @throws IllegalArgumentException if {@code uri} starts with "XB/AT" and 
302         *                                  its length is lesser than 8 (XB/AT/XX).
303         * @throws InterfaceNotOpenException if this device connection is not open.
304         * @throws NullPointerException if {@code ipv6Address == null} or 
305         *                              if {@code uri == null} or 
306         *                              if {@code method == null}.
307         * @throws TimeoutException if there is a timeout sending the data.
308         * @throws XBeeException if there is any other XBee related exception.
309         * 
310         * @see #getReceiveTimeout()
311         * @see #sendCoAPData(Inet6Address, String, HTTPMethodEnum, byte[])
312         * @see #sendCoAPDataAsync(Inet6Address, String, HTTPMethodEnum, byte[])
313         * @see #sendCoAPDataAsync(Inet6Address, String, HTTPMethodEnum, boolean, byte[])
314         * @see #setReceiveTimeout(int)
315         * @see com.digi.xbee.api.models.HTTPMethodEnum
316         * @see java.net.Inet6Address
317         */
318        public byte[] sendCoAPData(Inet6Address ipv6Address, String uri, HTTPMethodEnum method,
319                        boolean applyChanges, byte[] data) throws TimeoutException, IllegalArgumentException, XBeeException {
320                return sendCoAPData(ipv6Address, uri, method, applyChanges, data, false);
321        }
322        
323        /**
324         * Sends the provided CoAP IPv6 data to the given IPv6 address and port 
325         * asynchronously using the specified IPv6 protocol.
326         * 
327         * <p>Asynchronous transmissions do not wait for answer from the remote 
328         * device or for transmit status packet.</p>
329         * 
330         * <p>For blocking operations use the method 
331         * {@link #sendCoAPData(Inet6Address, String, HTTPMethodEnum, byte[])}.</p>
332         * 
333         * @param ipv6Address The IPv6 address to send CoAP IPv6 data to.
334         * @param uri Uniform Resource Identifier. Every CoAP message must have a 
335         *            valid URI string and must meet the following criteria. There 
336         *            are built-in CoAP URIs:
337         *            <ul>
338         *              <li><b>CoAPURI.URI_DATA_TRANSMISSION:</b> "XB/TX" 
339         *              for data transmissions (PUT)</li>
340         *              <li><b>CoAPURI.URI_AT_COMMAND:</b> "XB/AT" for 
341         *              AT Command operation (PUT or GET). After the URI, an AT command 
342         *              needs to be specified, for example: 
343         *              CoAPURI.URI_AT_COMMAND + "/NI"</li>
344         *              <li><b>CoAPURI.URI_IO_SAMPLING:</b> "XB/IO" for 
345         *              IO operation (POST)</li>
346         *            </ul>
347         * @param method HTTP method used for the transmission.
348         * @param data Byte array containing the CoAP IPv6 data to be sent.
349         * 
350         * @throws IllegalArgumentException if {@code uri} starts with "XB/AT" and 
351         *                                  its length is lesser than 8 (XB/AT/XX).
352         * @throws InterfaceNotOpenException if this device connection is not open.
353         * @throws NullPointerException if {@code ipv6Address == null} or 
354         *                              if {@code uri == null} or 
355         *                              if {@code method == null}.
356         * @throws TimeoutException if there is a timeout sending the data.
357         * @throws XBeeException if there is any other XBee related exception.
358         * 
359         * @see #getReceiveTimeout()
360         * @see #sendCoAPData(Inet6Address, String, HTTPMethodEnum, byte[])
361         * @see #sendCoAPData(Inet6Address, String, HTTPMethodEnum, boolean, byte[])
362         * @see #sendCoAPDataAsync(Inet6Address, String, HTTPMethodEnum, boolean, byte[])
363         * @see #setReceiveTimeout(int)
364         * @see com.digi.xbee.api.models.HTTPMethodEnum
365         * @see java.net.Inet6Address
366         */
367        public void sendCoAPDataAsync(Inet6Address ipv6Address, String uri,
368                        HTTPMethodEnum method, byte[] data) throws TimeoutException, IllegalArgumentException, XBeeException {
369                boolean applyChanges = uri.startsWith(CoAPURI.URI_AT_COMMAND);
370                sendCoAPData(ipv6Address, uri, method, applyChanges, data, true);
371        }
372        
373        /**
374         * Sends the provided CoAP IPv6 data to the given IPv6 address and port 
375         * asynchronously using the specified IPv6 protocol.
376         * 
377         * <p>Asynchronous transmissions do not wait for answer from the remote 
378         * device or for transmit status packet.</p>
379         * 
380         * <p>For blocking operations use the method 
381         * {@link #sendCoAPData(Inet6Address, String, HTTPMethodEnum, boolean, byte[])}.</p>
382         * 
383         * @param ipv6Address The IPv6 address to send CoAP IPv6 data to.
384         * @param uri Uniform Resource Identifier. Every CoAP message must have a 
385         *            valid URI string and must meet the following criteria. There 
386         *            are built-in CoAP URIs:
387         *            <ul>
388         *              <li><b>CoAPURI.URI_DATA_TRANSMISSION:</b> "XB/TX" 
389         *              for data transmissions (PUT)</li>
390         *              <li><b>CoAPURI.URI_AT_COMMAND:</b> "XB/AT" for 
391         *              AT Command operation (PUT or GET). After the URI, an AT command 
392         *              needs to be specified, for example: 
393         *              CoAPURI.URI_AT_COMMAND + "/NI"</li>
394         *              <li><b>CoAPURI.URI_IO_SAMPLING:</b> "XB/IO" for 
395         *              IO operation (POST)</li>
396         *            </ul>
397         * @param method HTTP method used for the transmission.
398         * @param applyChanges {@code true} to apply the changes after sending the 
399         *                     packet, {@code false} otherwise.
400         * @param data Byte array containing the CoAP IPv6 data to be sent.
401         * 
402         * @throws IllegalArgumentException if {@code uri} starts with "XB/AT" and 
403         *                                  its length is lesser than 8 (XB/AT/XX).
404         * @throws InterfaceNotOpenException if this device connection is not open.
405         * @throws NullPointerException if {@code ipv6Address == null} or 
406         *                              if {@code uri == null} or 
407         *                              if {@code method == null}.
408         * @throws TimeoutException if there is a timeout sending the data.
409         * @throws XBeeException if there is any other XBee related exception.
410         * 
411         * @see #getReceiveTimeout()
412         * @see #sendCoAPData(Inet6Address, String, HTTPMethodEnum, byte[])
413         * @see #sendCoAPData(Inet6Address, String, HTTPMethodEnum, boolean, byte[])
414         * @see #sendCoAPDataAsync(Inet6Address, String, HTTPMethodEnum, byte[])
415         * @see #setReceiveTimeout(int)
416         * @see com.digi.xbee.api.models.HTTPMethodEnum
417         * @see java.net.Inet6Address
418         */
419        public void sendCoAPDataAsync(Inet6Address ipv6Address, String uri, HTTPMethodEnum method,
420                        boolean applyChanges, byte[] data) throws TimeoutException, IllegalArgumentException, XBeeException {
421                sendCoAPData(ipv6Address, uri, method, applyChanges, data, true);
422        }
423        
424        /**
425         * Sends the provided CoAP IPv6 data to the given IPv6 address and port 
426         * using the specified IPv6 protocol.
427         * 
428         * <p>CoAP transmissions can be performed synchronously or asynchronously. 
429         * Synchronous operations block till a success or error response arrives 
430         * or the configured receive timeout expires. Asynchronous transmissions
431         * do not wait for answer from the remote device or for transmit status 
432         * packet.</p>
433         * 
434         * <p>The receive timeout is configured using the {@code setReceiveTimeout}
435         * method and can be consulted with {@code getReceiveTimeout} method.</p>
436         * 
437         * <p>For synchronous operations use these methods:</p>
438         * <ul>
439         *   <li>{@link #sendCoAPData(Inet6Address, String, HTTPMethodEnum, byte[])}.</li>
440         *   <li>{@link #sendCoAPData(Inet6Address, String, HTTPMethodEnum, boolean, byte[])}.</li>
441         * </ul>
442         * <p>For asynchronous operations use these ones:</p>
443         * <ul>
444         *   <li>{@link #sendCoAPDataAsync(Inet6Address, String, HTTPMethodEnum, byte[])}.</li>
445         *   <li>{@link #sendCoAPDataAsync(Inet6Address, String, HTTPMethodEnum, boolean, byte[])}.</li>
446         * </ul>
447         * 
448         * @param ipv6Address The IPv6 address to send CoAP IPv6 data to.
449         * @param uri Uniform Resource Identifier. Every CoAP message must have a 
450         *            valid URI string and must meet the following criteria. There 
451         *            are built-in CoAP URIs:
452         *            <ul>
453         *              <li><b>CoAPURI.URI_DATA_TRANSMISSION:</b> "XB/TX" 
454         *              for data transmissions (PUT)</li>
455         *              <li><b>CoAPURI.URI_AT_COMMAND:</b> "XB/AT" for 
456         *              AT Command operation (PUT or GET). After the URI, an AT command 
457         *              needs to be specified, for example: 
458         *              CoAPURI.URI_AT_COMMAND + "/NI"</li>
459         *              <li><b>CoAPURI.URI_IO_SAMPLING:</b> "XB/IO" for 
460         *              IO operation (POST)</li>
461         *            </ul>
462         * @param method HTTP method used for the transmission.
463         * @param applyChanges {@code true} to apply the changes after sending the 
464         *                     packet, {@code false} otherwise.
465         * @param data Byte array containing the CoAP IPv6 data to be sent.
466         * @param async {@code true} to make an asynchronous transmission, {@code false} 
467         *              to block till a success or error response arrives or the 
468         *              configured receive timeout expires .
469         * 
470         * @return A byte array containing the response, if any. Otherwise, {@code null}.
471         * 
472         * @throws IllegalArgumentException if {@code uri} starts with "XB/AT" and 
473         *                                  its length is lesser than 8 (XB/AT/XX).
474         * @throws InterfaceNotOpenException if this device connection is not open.
475         * @throws NullPointerException if {@code ipv6Address == null} or 
476         *                              if {@code uri == null} or 
477         *                              if {@code method == null}.
478         * @throws TimeoutException if there is a timeout sending the data.
479         * @throws XBeeException if there is any other XBee related exception.
480         * 
481         * @see #getReceiveTimeout()
482         * @see #sendCoAPData(Inet6Address, String, HTTPMethodEnum, byte[])
483         * @see #sendCoAPData(Inet6Address, String, HTTPMethodEnum, boolean, byte[])
484         * @see #sendCoAPDataAsync(Inet6Address, String, HTTPMethodEnum, byte[])
485         * @see #sendCoAPDataAsync(Inet6Address, String, HTTPMethodEnum, boolean, byte[])
486         * @see #setReceiveTimeout(int)
487         * @see com.digi.xbee.api.models.HTTPMethodEnum
488         * @see java.net.Inet6Address
489         */
490        private byte[] sendCoAPData(Inet6Address ipv6Address, String uri, HTTPMethodEnum method,
491                        boolean applyChanges, byte[] data, boolean async) throws TimeoutException, IllegalArgumentException, XBeeException {
492                if (ipv6Address == null)
493                        throw new NullPointerException("IPv6 address cannot be null");
494                if (uri == null)
495                        throw new NullPointerException("Uri cannot be null");
496                if (method == null)
497                        throw new NullPointerException("HTTP method cannot be null");
498                
499                // If AT command uri is used but no AT command is specified throw an error.
500                if (uri.startsWith(CoAPURI.URI_AT_COMMAND) 
501                        && uri.length() < CoAPURI.URI_AT_COMMAND.length() + 3)
502                        throw new IllegalArgumentException("AT command URI must contain an AT command.");
503                
504                // Check if device is remote.
505                if (isRemote())
506                        throw new OperationNotSupportedException("Cannot send CoAP IPv6 data from a remote device.");
507                
508                if (async)
509                        logger.debug(toString() + "Sending CoAP IPv6 data asynchronously to {} >> {}.", ipv6Address,
510                                        HexUtils.prettyHexString(data));
511                else
512                        logger.debug(toString() + "Sending CoAP IPv6 data to {} >> {}.", ipv6Address,
513                                        HexUtils.prettyHexString(data));
514                
515                CoAPTxRequestPacket coAPPacket = new CoAPTxRequestPacket(getNextFrameID(),
516                                applyChanges ? RemoteATCommandOptions.OPTION_APPLY_CHANGES: RemoteATCommandOptions.OPTION_NONE,
517                                method, ipv6Address, uri, data);
518                
519                // Check for a transmit status and CoAP RX Response.
520                return sendAndCheckCoAPPacket(coAPPacket, async);
521        }
522        
523        /*
524         * (non-Javadoc)
525         * @see com.digi.xbee.api.IPv6Device#sendIPData(java.net.Inet6Address, int, com.digi.xbee.api.models.IPProtocol, byte[])
526         */
527        @Override
528        public void sendIPData(Inet6Address ipv6Address, int destPort,
529                        IPProtocol protocol, byte[] data) throws TimeoutException,
530                        XBeeException {
531                if (protocol != IPProtocol.UDP && protocol != IPProtocol.COAP)
532                        throw new IllegalArgumentException(ERROR_PROTOCOL_ILLEGAL);
533                super.sendIPData(ipv6Address, destPort, protocol, data);
534        }
535        
536        /*
537         * (non-Javadoc)
538         * @see com.digi.xbee.api.IPv6Device#sendIPDataAsync(java.net.Inet6Address, int, com.digi.xbee.api.models.IPProtocol, byte[])
539         */
540        @Override
541        public void sendIPDataAsync(Inet6Address ipv6Address, int destPort,
542                        IPProtocol protocol, byte[] data) throws XBeeException {
543                if (protocol != IPProtocol.UDP && protocol != IPProtocol.COAP)
544                        throw new IllegalArgumentException(ERROR_PROTOCOL_ILLEGAL);
545                super.sendIPDataAsync(ipv6Address, destPort, protocol, data);
546        }
547}