    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.models;
    013
    014import java.util.Arrays;
    015
    016import com.digi.xbee.api.utils.HexUtils;
    017
    018/**
    019 * This class represents a 16-bit network address.
    020 *
    021 * <p>This address is only applicable for:</p>
    022 * <ul>
    023 *   <li>802.15.4</li>
    024 *   <li>ZigBee</li>
    025 *   <li>ZNet 2.5</li>
    026 *   <li>XTend (Legacy)</li>
    027 * </ul>
    028 *
    029 * <p>DigiMesh and Point-to-Multipoint protocols don't support 16-bit
    030 * addressing.</p>
    031 *
    032 * <p>Each device has its own 16-bit address which is unique in the network.
    033 * It is automatically assigned when the radio joins the network for ZigBee
    034 * and ZNet 2.5, and manually configured in 802.15.4 radios.</p>
    035 *
    036 */
    037public final class XBee16BitAddress {
    038
    039        // Constants
    040        /**
    041         * 16-bit address reserved for the coordinator (value: 0000).
    042         */
    043        public static final XBee16BitAddress COORDINATOR_ADDRESS = new XBee16BitAddress("0000");
    044        /**
    045         * 16-bit broadcast address (value: FFFF).
    046         */
    047        public static final XBee16BitAddress BROADCAST_ADDRESS = new XBee16BitAddress("FFFF");
    048        /**
    049         * 16-bit unknown address (value: FFFE).
    050         */
    051        public static final XBee16BitAddress UNKNOWN_ADDRESS = new XBee16BitAddress("FFFE");
    052
    053        /**
    054         * Pattern for the 16-bit address string: {@value}.
    055         */
    056        private static final String XBEE_16_BIT_ADDRESS_PATTERN = "(0[xX])?[0-9a-fA-F]{1,4}";
    057
    058        private static final int HASH_SEED = 23;
    059
    060        // Variables
    061        private final byte[] address;
    062
    063        /**
    064         * Class constructor. Instantiates a new object of type
    065         * {@code XBee16BitAddress} with the given parameters.
    066         *
    067         * @param hsb High significant byte of the address.
    068         * @param lsb Low significant byte of the address.
    069         *
    070         * @throws IllegalArgumentException if {@code hsb > 255} or
    071         *                                  if {@code hsb < 0} or
    072         *                                  if {@code lsb > 255} or
    073         *                                  if {@code lsb < 0}.
    074         */
    075        public XBee16BitAddress(int hsb, int lsb) {
    076                if (hsb > 255 || hsb < 0)
    077                        throw new IllegalArgumentException("HSB must be between 0 and 255.");
    078                if (lsb > 255 || lsb < 0)
    079                        throw new IllegalArgumentException("LSB must be between 0 and 255.");
    080
    081                address = new byte[2];
    082                address[0] = (byte) hsb;
    083                address[1] = (byte) lsb;
    084        }
    085
    086        /**
    087         * Class constructor. Instantiates a new object of type
    088         * {@code XBee16BitAddress} with the given parameters.
    089         *
    090         * @param address The 16-bit address as byte array.
    091         *
    092         * @throws IllegalArgumentException if {@code address.length < 1} or
    093         *                                  if {@code address.length > 2}.
    094         * @throws NullPointerException if {@code address == null}.
    095         */
    096        public XBee16BitAddress(byte[] address) {
    097                if (address == null)
    098                        throw new NullPointerException("Address cannot be null.");
    099                if (address.length < 1)
    100                        throw new IllegalArgumentException("Address must contain at least 1 byte.");
    101                if (address.length > 2)
    102                        throw new IllegalArgumentException("Address cannot contain more than 2 bytes.");
    103
    104                // Check array size.
    105                this.address = new byte[2];
    106                int diff = this.address.length - address.length;
    107                for (int i = 0; i < diff; i++)
    108                        this.address[i] = 0;
    109                for (int i = diff; i < this.address.length; i++)
    110                        this.address[i] = address[i - diff];
    111        }
    112
    113        /**
    114         * Class constructor. Instantiates a new object of type
    115         * {@code XBee16BitAddress} with the given parameters.
    116         *
    117         * <p>The string must be the hexadecimal representation of a 16-bit
    118         * address.</p>
    119         *
    120         * @param address String containing the 16-bit address.
    121         *
    122         * @throws IllegalArgumentException if {@code address.length() < 1} or
    123         *                                  if {@code address} contains
    124         *                                  non-hexadecimal characters and is longer
    125         *                                  than 8 bytes.
    126         * @throws NullPointerException if {@code address == null}.
    127         */
    128        public XBee16BitAddress(String address) {
    129                if (address == null)
    130                        throw new NullPointerException("Address cannot be null.");
    131                if (address.length() < 1)
    132                        throw new IllegalArgumentException("Address must contain at least 1 character.");
    133                if (!address.matches(XBEE_16_BIT_ADDRESS_PATTERN))
    134                        throw new IllegalArgumentException("Address must follow this pattern: (0x)XXXX.");
    135
    136                // Convert the string into a byte array.
    137                byte[] byteAddress = HexUtils.hexStringToByteArray(address);
    138                // Check array size.
    139                this.address = new byte[2];
    140                int diff = this.address.length - byteAddress.length;
    141                for (int i = 0; i < diff; i++)
    142                        this.address[i] = 0;
    143                for (int i = diff; i < this.address.length; i++)
    144                        this.address[i] = byteAddress[i - diff];
    145        }
    146
    147        /**
    148         * Returns the address high significant byte.
    149         *
    150         * @return Address high significant byte.
    151         */
    152        public int getHsb() {
    153                return address[0];
    154        }
    155
    156        /**
    157         * Returns the address low significant byte.
    158         *
    159         * @return Address low significant byte.
    160         */
    161        public int getLsb() {
    162                return address[1];
    163        }
    164
    165        /**
    166         * Returns the 16-bit address value in byte array format.
    167         *
    168         * @return Address value as byte array.
    169         */
    170        public byte[] getValue() {
    171                return Arrays.copyOf(address, address.length);
    172        }
    173
    174        /*
    175         * (non-Javadoc)
    176         * @see java.lang.Object#equals(java.lang.Object)
    177         */
    178        @Override
    179        public boolean equals(Object obj) {
    180                if (!(obj instanceof XBee16BitAddress))
    181                        return false;
    182                XBee16BitAddress addr = (XBee16BitAddress)obj;
    183                return Arrays.equals(addr.getValue(), getValue());
    184        }
    185
    186        /*
    187         * (non-Javadoc)
    188         * @see java.lang.Object#hashCode()
    189         */
    190        @Override
    191        public int hashCode() {
    192                int hash = HASH_SEED;
    193                for (byte b:getValue())
    194                        hash = hash * (hash + b);
    195                return hash;
    196        }
    197
    198        /*
    199         * (non-Javadoc)
    200         * @see java.lang.Object#toString()
    201         */
    202        @Override
    203        public String toString() {
    204                return HexUtils.byteArrayToHexString(address);
    205        }
    206}