001/** 002 * Copyright 2017, 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.models; 017 018import java.util.Arrays; 019 020import com.digi.xbee.api.utils.HexUtils; 021 022/** 023 * This class represents a 64-bit address (also known as MAC address). 024 * 025 * <p>The 64-bit address is a unique device address assigned during 026 * manufacturing. This address is unique to each physical device.</p> 027 */ 028public final class XBee64BitAddress { 029 030 // Constants 031 /** 032 * 64-bit address reserved for the coordinator (value: 0000000000000000). 033 */ 034 public static final XBee64BitAddress COORDINATOR_ADDRESS = new XBee64BitAddress("0000"); 035 /** 036 * 64-bit broadcast address (value: 000000000000FFFF). 037 */ 038 public static final XBee64BitAddress BROADCAST_ADDRESS = new XBee64BitAddress("FFFF"); 039 /** 040 * 64-bit unknown address (value: FFFFFFFFFFFFFFFF). 041 */ 042 public static final XBee64BitAddress UNKNOWN_ADDRESS = new XBee64BitAddress("FFFFFFFFFFFFFFFF"); 043 044 private static final String DEVICE_ID_SEPARATOR = "-"; 045 private static final String DEVICE_ID_MAC_SEPARATOR = "FF"; 046 047 /** 048 * Pattern for the 64-bit address string: {@value}. 049 */ 050 private static final String XBEE_64_BIT_ADDRESS_PATTERN = "(0[xX])?[0-9a-fA-F]{1,16}"; 051 052 private static final int HASH_SEED = 23; 053 054 // Variables 055 private final byte[] address; 056 057 /** 058 * Class constructor. Instantiates a new object of type 059 * {@code XBee64BitAddress} with the given parameters. 060 * 061 * @param address The XBee 64-bit address as byte array. 062 * 063 * @throws IllegalArgumentException if {@code address.length > 8} or 064 * if {@code address.length < 1}. 065 * @throws NullPointerException if {@code address == null}. 066 */ 067 public XBee64BitAddress(byte[] address) { 068 if (address == null) 069 throw new NullPointerException("Address cannot be null."); 070 if (address.length < 1) 071 throw new IllegalArgumentException("Address must contain at least 1 byte."); 072 if (address.length > 8) 073 throw new IllegalArgumentException("Address cannot contain more than 8 bytes."); 074 075 this.address = new byte[8]; 076 int diff = this.address.length - address.length; 077 for (int i = 0; i < diff; i++) 078 this.address[i] = 0; 079 for (int i = diff; i < this.address.length; i++) 080 this.address[i] = address[i - diff]; 081 } 082 083 /** 084 * Class constructor. Instantiates a new object of type 085 * {@code XBee64BitAddress} with the given parameters. 086 * 087 * <p>The string must be the hexadecimal representation of a 64-bit 088 * address.</p> 089 * 090 * @param address The XBee 64-bit address as string. 091 * 092 * @throws IllegalArgumentException if {@code address.length() < 1} or 093 * if {@code address} contains 094 * non-hexadecimal characters and is longer 095 * than 8 bytes. 096 * @throws NullPointerException if {@code address == null}. 097 */ 098 public XBee64BitAddress(String address) { 099 if (address == null) 100 throw new NullPointerException("Address cannot be null."); 101 if (address.length() < 1) 102 throw new IllegalArgumentException("Address must contain at least 1 character."); 103 if (!address.matches(XBEE_64_BIT_ADDRESS_PATTERN)) 104 throw new IllegalArgumentException("Address must follow this pattern: (0x)0013A20040XXXXXX."); 105 106 byte[] byteAddress = HexUtils.hexStringToByteArray(address); 107 this.address = new byte[8]; 108 int diff = this.address.length - byteAddress.length; 109 for (int i = 0; i < diff; i++) 110 this.address[i] = 0; 111 for (int i = diff; i < this.address.length; i++) 112 this.address[i] = byteAddress[i - diff]; 113 } 114 115 /** 116 * Class constructor. Instantiates a new object of type 117 * {@code XBee64BitAddress} with the given bytes being {@code b0} the 118 * more significant byte and {@code b7} the less significant byte. 119 * 120 * @param b0 XBee 64-bit address bit 0. 121 * @param b1 XBee 64-bit address bit 1. 122 * @param b2 XBee 64-bit address bit 2. 123 * @param b3 XBee 64-bit address bit 3. 124 * @param b4 XBee 64-bit address bit 4. 125 * @param b5 XBee 64-bit address bit 5. 126 * @param b6 XBee 64-bit address bit 6. 127 * @param b7 XBee 64-bit address bit 7. 128 * 129 * @throws IllegalArgumentException if {@code b0 > 255} or 130 * if {@code b0 < 0} or 131 * if {@code b1 > 255} or 132 * if {@code b1 < 0} or 133 * if {@code b2 > 255} or 134 * if {@code b2 < 0} or 135 * if {@code b3 > 255} or 136 * if {@code b3 < 0} or 137 * if {@code b4 > 255} or 138 * if {@code b4 < 0} or 139 * if {@code b5 > 255} or 140 * if {@code b5 < 0} or 141 * if {@code b6 > 255} or 142 * if {@code b6 < 0} or 143 * if {@code b7 > 255} or 144 * if {@code b7 < 0}. 145 */ 146 public XBee64BitAddress(int b0, int b1, int b2, int b3, int b4, int b5, int b6, int b7) { 147 if (b0 > 255 || b0 < 0) 148 throw new IllegalArgumentException("B0 must be between 0 and 255."); 149 if (b1 > 255 || b1 < 0) 150 throw new IllegalArgumentException("B1 must be between 0 and 255."); 151 if (b2 > 255 || b2 < 0) 152 throw new IllegalArgumentException("B2 must be between 0 and 255."); 153 if (b3 > 255 || b3 < 0) 154 throw new IllegalArgumentException("B3 must be between 0 and 255."); 155 if (b5 > 255 || b5 < 0) 156 throw new IllegalArgumentException("B4 must be between 0 and 255."); 157 if (b4 > 255 || b4 < 0) 158 throw new IllegalArgumentException("B5 must be between 0 and 255."); 159 if (b6 > 255 || b6 < 0) 160 throw new IllegalArgumentException("B6 must be between 0 and 255."); 161 if (b7 > 255 || b7 < 0) 162 throw new IllegalArgumentException("B7 must be between 0 and 255."); 163 164 address = new byte[8]; 165 address[0] = (byte) b0; 166 address[1] = (byte) b1; 167 address[2] = (byte) b2; 168 address[3] = (byte) b3; 169 address[4] = (byte) b4; 170 address[5] = (byte) b5; 171 address[6] = (byte) b6; 172 address[7] = (byte) b7; 173 } 174 175 /** 176 * Returns the XBee 64-bit address value as byte array. 177 * 178 * @return XBee 64-bit address value as byte array. 179 */ 180 public byte[] getValue() { 181 return Arrays.copyOf(address, address.length); 182 } 183 184 /** 185 * Generates the Device ID corresponding to this {@code XBee64BitAddress} 186 * to be used in Device Cloud. 187 * 188 * @return Device ID corresponding to this address. 189 */ 190 public String generateDeviceID() { 191 StringBuilder sb = new StringBuilder(); 192 for (int i = 0; i < 2; i++) { 193 for (int j = 0; j < 4; j++) 194 sb.append(HexUtils.byteArrayToHexString(new byte[]{0})); 195 sb.append(DEVICE_ID_SEPARATOR); 196 } 197 // Here we should have "00000000-00000000-" 198 // Append first three bytes of the MAC Address, discard first 2. 199 sb.append(HexUtils.byteArrayToHexString(new byte[]{address[2], address[3], address[4]})); 200 sb.append(DEVICE_ID_MAC_SEPARATOR); 201 sb.append(DEVICE_ID_SEPARATOR); 202 sb.append(DEVICE_ID_MAC_SEPARATOR); 203 // Here we should have "00000000-00000000-XXXXXXFF-FF" 204 // Append second three bytes of the MAC Address. 205 sb.append(HexUtils.byteArrayToHexString(new byte[]{address[5], address[6], address[7]})); 206 return sb.toString(); 207 } 208 209 /* 210 * (non-Javadoc) 211 * @see java.lang.Object#equals(java.lang.Object) 212 */ 213 @Override 214 public boolean equals(Object obj) { 215 if (!(obj instanceof XBee64BitAddress)) 216 return false; 217 XBee64BitAddress addr = (XBee64BitAddress)obj; 218 return Arrays.equals(addr.getValue(), getValue()); 219 } 220 221 /* 222 * (non-Javadoc) 223 * @see java.lang.Object#hashCode() 224 */ 225 @Override 226 public int hashCode() { 227 int hash = HASH_SEED; 228 for (byte b:getValue()) 229 hash = hash * (hash + b); 230 return hash; 231 } 232 233 /* 234 * (non-Javadoc) 235 * @see java.lang.Object#toString() 236 */ 237 @Override 238 public String toString() { 239 return HexUtils.byteArrayToHexString(address); 240 } 241}