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