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