1616package com .digi .xbee .api ;
1717
1818import java .io .IOException ;
19+ import java .net .Inet6Address ;
20+ import java .net .UnknownHostException ;
1921import java .util .ArrayList ;
2022import java .util .Arrays ;
2123import java .util .Set ;
5557import com .digi .xbee .api .models .HardwareVersion ;
5658import com .digi .xbee .api .models .PowerLevel ;
5759import com .digi .xbee .api .models .RemoteATCommandOptions ;
60+ import com .digi .xbee .api .models .RestFulStatusEnum ;
5861import com .digi .xbee .api .models .XBee16BitAddress ;
5962import com .digi .xbee .api .models .XBee64BitAddress ;
6063import com .digi .xbee .api .models .OperatingMode ;
7376import com .digi .xbee .api .packet .raw .RX16IOPacket ;
7477import com .digi .xbee .api .packet .raw .RX64IOPacket ;
7578import com .digi .xbee .api .packet .raw .TXStatusPacket ;
79+ import com .digi .xbee .api .packet .thread .CoAPRxResponsePacket ;
80+ import com .digi .xbee .api .packet .thread .CoAPTxRequestPacket ;
81+ import com .digi .xbee .api .packet .thread .IPv6RemoteATCommandRequestPacket ;
82+ import com .digi .xbee .api .packet .thread .IPv6RemoteATCommandResponsePacket ;
7683import com .digi .xbee .api .utils .ByteUtils ;
7784import com .digi .xbee .api .utils .HexUtils ;
7885
@@ -133,6 +140,8 @@ public abstract class AbstractXBeeDevice {
133140 protected XBee16BitAddress xbee16BitAddress = XBee16BitAddress .UNKNOWN_ADDRESS ;
134141 protected XBee64BitAddress xbee64BitAddress = XBee64BitAddress .UNKNOWN_ADDRESS ;
135142
143+ protected Inet6Address ipv6Address = null ;
144+
136145 protected int currentFrameID = 0xFF ;
137146 protected int receiveTimeout = DEFAULT_RECEIVE_TIMETOUT ;
138147
@@ -384,6 +393,73 @@ public AbstractXBeeDevice(XBeeDevice localXBeeDevice, XBee64BitAddress addr64,
384393 connectionInterface .getClass ().getSimpleName ());
385394 }
386395
396+ /**
397+ * Class constructor. Instantiates a new {@code RemoteXBeeDevice} object
398+ * with the given local {@code XBeeDevice} which contains the connection
399+ * interface to be used.
400+ *
401+ * @param localXBeeDevice The local XBee device that will behave as
402+ * connection interface to communicate with this
403+ * remote XBee device.
404+ * @param ipv6Addr The IPv6 address to identify this XBee device.
405+ *
406+ * @throws IllegalArgumentException If {@code localXBeeDevice.isRemote() == true}.
407+ * @throws NullPointerException if {@code localXBeeDevice == null} or
408+ * if {@code ipv6Addr == null}.
409+ *
410+ * @see #AbstractXBeeDevice(IConnectionInterface)
411+ * @see #AbstractXBeeDevice(String, int)
412+ * @see #AbstractXBeeDevice(String, SerialPortParameters)
413+ * @see #AbstractXBeeDevice(String, int, int, int, int, int)
414+ * @see #AbstractXBeeDevice(Context, int)
415+ * @see #AbstractXBeeDevice(Context, int, AndroidUSBPermissionListener)
416+ * @see java.net.Inet6Address
417+ */
418+ public AbstractXBeeDevice (XBeeDevice localXBeeDevice , Inet6Address ipv6Addr ) {
419+ this (localXBeeDevice , ipv6Addr , null );
420+ }
421+
422+ /**
423+ * Class constructor. Instantiates a new {@code RemoteXBeeDevice} object
424+ * with the given local {@code XBeeDevice} which contains the connection
425+ * interface to be used.
426+ *
427+ * @param localXBeeDevice The local XBee device that will behave as
428+ * connection interface to communicate with this
429+ * remote XBee device.
430+ * @param ipv6Addr The IPv6 address to identify this XBee device.
431+ * @param id The node identifier of this XBee device. It might be
432+ * {@code null}.
433+ *
434+ * @throws IllegalArgumentException If {@code localXBeeDevice.isRemote() == true}.
435+ * @throws NullPointerException if {@code localXBeeDevice == null} or
436+ * if {@code ipv6Addr == null}.
437+ *
438+ * @see #AbstractXBeeDevice(IConnectionInterface)
439+ * @see #AbstractXBeeDevice(String, int)
440+ * @see #AbstractXBeeDevice(String, SerialPortParameters)
441+ * @see #AbstractXBeeDevice(String, int, int, int, int, int)
442+ * @see #AbstractXBeeDevice(Context, int)
443+ * @see #AbstractXBeeDevice(Context, int, AndroidUSBPermissionListener)
444+ * @see java.net.Inet6Address
445+ */
446+ public AbstractXBeeDevice (XBeeDevice localXBeeDevice , Inet6Address ipv6Addr , String id ) {
447+ if (localXBeeDevice == null )
448+ throw new NullPointerException ("Local XBee device cannot be null." );
449+ if (ipv6Addr == null )
450+ throw new NullPointerException ("XBee IPv6 address of the device cannot be null." );
451+ if (localXBeeDevice .isRemote ())
452+ throw new IllegalArgumentException ("The given local XBee device is remote." );
453+
454+ this .localXBeeDevice = localXBeeDevice ;
455+ this .connectionInterface = localXBeeDevice .getConnectionInterface ();
456+ this .ipv6Address = ipv6Addr ;
457+ this .nodeID = id ;
458+ this .logger = LoggerFactory .getLogger (this .getClass ());
459+ logger .debug (toString () + "Using the connection interface {}." ,
460+ connectionInterface .getClass ().getSimpleName ());
461+ }
462+
387463 /**
388464 * Returns the connection interface associated to this XBee device.
389465 *
@@ -515,6 +591,19 @@ public XBee64BitAddress get64BitAddress() {
515591 return xbee64BitAddress ;
516592 }
517593
594+ /**
595+ * Returns the IPv6 address of this IPv6 device.
596+ *
597+ * <p>To refresh this value use the {@link #readDeviceInfo()} method.</p>
598+ *
599+ * @return The IPv6 address of this IPv6 device.
600+ *
601+ * @see java.net.Inet6Address
602+ */
603+ public Inet6Address getIPv6Address () {
604+ return ipv6Address ;
605+ }
606+
518607 /**
519608 * Returns the Operating mode (AT, API or API escaped) of this XBee device
520609 * for a local device, and the operating mode of the local device used as
@@ -1017,16 +1106,21 @@ protected ATCommandResponse sendATCommand(ATCommand command)
10171106 // Create the corresponding AT command packet depending on if the device is local or remote.
10181107 XBeePacket packet ;
10191108 if (isRemote ()) {
1020- XBee16BitAddress remote16BitAddress = get16BitAddress ();
1021- if (remote16BitAddress == null )
1022- remote16BitAddress = XBee16BitAddress .UNKNOWN_ADDRESS ;
1023-
10241109 int remoteATCommandOptions = RemoteATCommandOptions .OPTION_NONE ;
10251110 if (isApplyConfigurationChangesEnabled ())
10261111 remoteATCommandOptions |= RemoteATCommandOptions .OPTION_APPLY_CHANGES ;
10271112
1028- packet = new RemoteATCommandPacket (getNextFrameID (), get64BitAddress (),
1029- remote16BitAddress , remoteATCommandOptions , command .getCommand (), command .getParameter ());
1113+ if (getXBeeProtocol () == XBeeProtocol .THREAD ) {
1114+ packet = new IPv6RemoteATCommandRequestPacket (getNextFrameID (), ipv6Address ,
1115+ remoteATCommandOptions , command .getCommand (), command .getParameter ());
1116+ } else {
1117+ XBee16BitAddress remote16BitAddress = get16BitAddress ();
1118+ if (remote16BitAddress == null )
1119+ remote16BitAddress = XBee16BitAddress .UNKNOWN_ADDRESS ;
1120+
1121+ packet = new RemoteATCommandPacket (getNextFrameID (), get64BitAddress (),
1122+ remote16BitAddress , remoteATCommandOptions , command .getCommand (), command .getParameter ());
1123+ }
10301124 } else {
10311125 if (isApplyConfigurationChangesEnabled ())
10321126 packet = new ATCommandPacket (getNextFrameID (), command .getCommand (), command .getParameter ());
@@ -1052,6 +1146,9 @@ protected ATCommandResponse sendATCommand(ATCommand command)
10521146 } else if (answerPacket instanceof RemoteATCommandResponsePacket ) {
10531147 RemoteATCommandResponsePacket r = (RemoteATCommandResponsePacket )answerPacket ;
10541148 response = new ATCommandResponse (command , r .getCommandValue (), r .getStatus ());
1149+ } else if (answerPacket instanceof IPv6RemoteATCommandResponsePacket ) {
1150+ IPv6RemoteATCommandResponsePacket r = (IPv6RemoteATCommandResponsePacket )answerPacket ;
1151+ response = new ATCommandResponse (command , r .getCommandValue (), r .getStatus ());
10551152 }
10561153
10571154 if (response != null && response .getResponse () != null )
@@ -1422,6 +1519,146 @@ else if (receivedPacket instanceof TXStatusPacket)
14221519 throw new TransmitException (status );
14231520 }
14241521
1522+ /**
1523+ * Sends the provided {@code CoAPTxRequestPacket} and determines if the
1524+ * transmission status and CoAP RX Response are success for synchronous
1525+ * transmissions.
1526+ *
1527+ * <p>If the status or the CoAP response are not successful, an
1528+ * {@code TransmitException} is thrown.</p>
1529+ *
1530+ * @param packet The {@code CoAPTxRequestPacket} to be sent.
1531+ * @param asyncTransmission Determines whether the transmission must be
1532+ * asynchronous.
1533+ *
1534+ * @return A byte array containing the RfData of the CoAP RX Response
1535+ * packet, if that field is not empty. In other cases, it will
1536+ * return {@code null}.
1537+ *
1538+ * @throws InterfaceNotOpenException if this device connection is not open.
1539+ * @throws NullPointerException if {@code packet == null}.
1540+ * @throws TransmitException if {@code packet} is not an instance of
1541+ * {@code TransmitStatusPacket} or
1542+ * if {@code packet} is not an instance of
1543+ * {@code TXStatusPacket} or
1544+ * if its transmit status is different than
1545+ * {@code XBeeTransmitStatus.SUCCESS}.
1546+ * @throws XBeeException if CoAP response packet is not received or it is
1547+ * not successful or if there is any other XBee
1548+ * related error.
1549+ *
1550+ * @see com.digi.xbee.api.packet.XBeePacket
1551+ */
1552+ protected byte [] sendAndCheckCoAPPacket (CoAPTxRequestPacket packet ,
1553+ boolean asyncTransmission ) throws TransmitException , XBeeException {
1554+ // Add listener to read CoAP response (when sending a CoAP transmission,
1555+ // a transmit status and a CoAP response are received by the sender)
1556+ ArrayList <CoAPRxResponsePacket > coapResponsePackets = new ArrayList <CoAPRxResponsePacket >();
1557+ IPacketReceiveListener listener = createCoAPResponseListener (coapResponsePackets );
1558+ addPacketListener (listener );
1559+
1560+ // Send the XBee packet.
1561+ XBeePacket receivedPacket = null ;
1562+ try {
1563+ if (asyncTransmission )
1564+ sendXBeePacketAsync (packet );
1565+ else
1566+ receivedPacket = sendXBeePacket (packet );
1567+ } catch (IOException e ) {
1568+ throw new XBeeException ("Error writing in the communication interface." , e );
1569+ }
1570+
1571+ // If the transmission is async. we are done.
1572+ if (asyncTransmission )
1573+ return null ;
1574+
1575+ if (receivedPacket == null )
1576+ throw new TransmitException (null );
1577+
1578+ // Verify Transmit status.
1579+ XBeeTransmitStatus status = null ;
1580+ if (receivedPacket instanceof TXStatusPacket )
1581+ status = ((TXStatusPacket )receivedPacket ).getTransmitStatus ();
1582+
1583+ if (status == null ||
1584+ (status != XBeeTransmitStatus .SUCCESS && status != XBeeTransmitStatus .SELF_ADDRESSED ))
1585+ throw new TransmitException (status );
1586+
1587+ // Verify CoAP response (only expect one CoAP RX Response packet).
1588+ CoAPRxResponsePacket coapRxPacket = null ;
1589+ try {
1590+ coapRxPacket = waitForCoAPRxResponsePacket (coapResponsePackets );
1591+ } finally {
1592+ // Always remove the packet listener from the list.
1593+ removePacketListener (listener );
1594+ }
1595+ if (coapRxPacket == null )
1596+ throw new XBeeException ("CoAP response was null." );
1597+ return coapRxPacket .getRfData ();
1598+ }
1599+
1600+ /**
1601+ * Returns the CoAP packet listener corresponding to the provided sent CoAP
1602+ * packet.
1603+ *
1604+ * <p>The listener will filter CoAP Rx Response packets (0x9C) and storing
1605+ * them in the provided responseList array.</p>
1606+ *
1607+ * @param coapResponsePackets List of CoAP Rx Response packets received.
1608+ *
1609+ * @return A CoAP packet receive listener.
1610+ *
1611+ * @see com.digi.xbee.api.listeners.IPacketReceiveListener
1612+ * @see com.digi.xbee.api.packet.thread.CoAPRxResponsePacket
1613+ */
1614+ private IPacketReceiveListener createCoAPResponseListener (final ArrayList <CoAPRxResponsePacket > coapResponsePackets ) {
1615+ IPacketReceiveListener listener = new IPacketReceiveListener () {
1616+
1617+ @ Override
1618+ public void packetReceived (XBeePacket receivedPacket ) {
1619+ if (receivedPacket instanceof CoAPRxResponsePacket ) {
1620+ coapResponsePackets .add ((CoAPRxResponsePacket )receivedPacket );
1621+ coapResponsePackets .notifyAll ();
1622+ }
1623+ }
1624+ };
1625+ return listener ;
1626+ }
1627+
1628+ /**
1629+ * Returns the CoAP Rx Response packet that comes in through the serial
1630+ * port in the given timeout.
1631+ *
1632+ * @param coapResponsePackets List of packets where the received packet will be stored.
1633+ *
1634+ * @return CoAP Rx Response packet received.
1635+ *
1636+ * @throws XBeeException if CoAP response packet is not received or it is
1637+ * not successful or if there is any other XBee
1638+ * related error.
1639+ */
1640+ private CoAPRxResponsePacket waitForCoAPRxResponsePacket (ArrayList <CoAPRxResponsePacket > coapResponsePackets ) throws XBeeException {
1641+ synchronized (coapResponsePackets ) {
1642+ try {
1643+ coapResponsePackets .wait (receiveTimeout );
1644+ } catch (InterruptedException e ) {}
1645+ }
1646+
1647+ if (!coapResponsePackets .isEmpty ()) {
1648+ RestFulStatusEnum responseStatus = coapResponsePackets .get (0 ).getStatus ();
1649+ if (responseStatus != RestFulStatusEnum .SUCCESS
1650+ && responseStatus != RestFulStatusEnum .CREATED
1651+ && responseStatus != RestFulStatusEnum .ACCEPTED
1652+ && responseStatus != RestFulStatusEnum .NON_AUTHORITATIVE
1653+ && responseStatus != RestFulStatusEnum .NO_CONTENT
1654+ && responseStatus != RestFulStatusEnum .RESET_CONTENT )
1655+ throw new XBeeException ("CoAP response had an unexpected status: " + responseStatus .toString ());
1656+ } else {
1657+ throw new XBeeException ("CoAP response was not received." );
1658+ }
1659+ return coapResponsePackets .get (0 );
1660+ }
1661+
14251662 /**
14261663 * Sets the configuration of the given IO line of this XBee device.
14271664 *
@@ -1775,6 +2012,46 @@ public XBee64BitAddress getDestinationAddress() throws TimeoutException, XBeeExc
17752012 return new XBee64BitAddress (address );
17762013 }
17772014
2015+ /**
2016+ * Sets the destination IPv6 address.
2017+ *
2018+ * @param ipv6Address Destination IPv6 address.
2019+ *
2020+ * @throws NullPointerException if {@code address == null}.
2021+ * @throws TimeoutException if there is a timeout setting the destination
2022+ * address.
2023+ * @throws XBeeException if there is any other XBee related exception.
2024+ *
2025+ * @see #getDestinationIPAddress()
2026+ * @see java.net.Inet6Address
2027+ */
2028+ public void setIPv6DestinationAddress (Inet6Address ipv6Address ) throws TimeoutException , XBeeException {
2029+ if (ipv6Address == null )
2030+ throw new NullPointerException ("Destination IPv6 address cannot be null." );
2031+
2032+ setParameter ("DL" , ipv6Address .getAddress ());
2033+ }
2034+
2035+ /**
2036+ * Returns the destination IPv6 address.
2037+ *
2038+ * @return The configured destination IPv6 address.
2039+ *
2040+ * @throws TimeoutException if there is a timeout reading the destination
2041+ * address.
2042+ * @throws XBeeException if there is any other XBee related exception.
2043+ *
2044+ * @see #setDestinationIPAddress(Inet6Address)
2045+ * @see java.net.Inet6Address
2046+ */
2047+ public Inet6Address getIPv6DestinationAddress () throws TimeoutException , XBeeException {
2048+ try {
2049+ return (Inet6Address ) Inet6Address .getByAddress (getParameter ("DL" ));
2050+ } catch (UnknownHostException e ) {
2051+ throw new XBeeException (e );
2052+ }
2053+ }
2054+
17782055 /**
17792056 * Sets the IO sampling rate to enable periodic sampling in this XBee
17802057 * device.
0 commit comments