1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.server.uwb.util; 17 18 import static com.android.server.uwb.data.UwbUciConstants.UWB_DEVICE_EXT_MAC_ADDRESS_LEN; 19 import static com.android.server.uwb.data.UwbUciConstants.UWB_DEVICE_SHORT_MAC_ADDRESS_LEN; 20 21 import androidx.annotation.NonNull; 22 import androidx.annotation.Nullable; 23 24 import java.nio.ByteBuffer; 25 import java.nio.ByteOrder; 26 27 /** Utility class for doing conversions, including bytes, hex strings, ints, and ASCII. */ 28 public class DataTypeConversionUtil { 29 30 private static final char[] HEX_ARRAY = { 31 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 32 }; 33 34 /** 35 * Conver the hex string to byte array. 36 */ hexStringToByteArray(String hex)37 public static byte[] hexStringToByteArray(String hex) { 38 // remove whitespace in the hex string. 39 hex = hex.replaceAll("\\s", ""); 40 41 int len = hex.length(); 42 if (len % 2 != 0) { 43 // Pad the hex string with a leading zero. 44 hex = String.format("0%s", hex); 45 len++; 46 } 47 byte[] data = new byte[len / 2]; 48 for (int i = 0; i < len; i += 2) { 49 data[i / 2] = 50 (byte) ((Character.digit(hex.charAt(i), 16) << 4) 51 | Character.digit(hex.charAt(i + 1), 16)); 52 } 53 return data; 54 } 55 56 /** 57 * Convert the byte array to hex string. 58 */ 59 @NonNull byteArrayToHexString(@ullable byte[] response)60 public static String byteArrayToHexString(@Nullable byte[] response) { 61 if (response == null) { 62 return ""; 63 } 64 return byteArrayToHexString(response, 0, response.length); 65 } 66 67 /** 68 * Convertt part of the byte array to hex string. 69 */ byteArrayToHexString( byte[] response, int startIndex, int endIndex)70 public static String byteArrayToHexString( 71 byte[] response, int startIndex, int endIndex) { 72 char[] hex = new char[(endIndex - startIndex) * 2]; 73 int v; 74 for (int i = 0; i < endIndex - startIndex; i++) { 75 v = unsignedByteToInt(response[startIndex + i]); 76 hex[i * 2] = HEX_ARRAY[v >> 4]; 77 hex[i * 2 + 1] = HEX_ARRAY[v & 0x0F]; 78 } 79 return new String(hex); 80 } 81 82 /** 83 * Convert the byte to int. 84 */ unsignedByteToInt(byte b)85 public static int unsignedByteToInt(byte b) { 86 return b & 0xFF; 87 } 88 89 /** 90 * Convert the int to byte. 91 */ unsignedIntToByte(int n)92 public static byte unsignedIntToByte(int n) { 93 return (byte) (n & 0xFF); 94 } 95 96 /** 97 * Convert the byte array to int16 using big endian. 98 */ byteArrayToI16(byte[] bytes)99 public static short byteArrayToI16(byte[] bytes) { 100 if (bytes.length != 2) { 101 throw new NumberFormatException("Expected length 2 but was " + bytes.length); 102 } 103 return ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getShort(); 104 } 105 106 /** 107 * Convert the byte array to int using big endian. 108 */ byteArrayToI32(byte[] bytes)109 public static int byteArrayToI32(byte[] bytes) { 110 if (bytes.length != 4) { 111 throw new NumberFormatException("Expected length 4 but was " + bytes.length); 112 } 113 return ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getInt(); 114 } 115 116 /** 117 * Convert the byte array with arbitrary size less than 5 to int using big endian. 118 */ arbitraryByteArrayToI32(byte[] bytes)119 public static int arbitraryByteArrayToI32(byte[] bytes) { 120 if (bytes.length > 4 || bytes.length < 1) { 121 throw new NumberFormatException("Expected length less than 5 but was " + bytes.length); 122 } 123 ByteBuffer byteBuffer = ByteBuffer.allocate(Integer.BYTES); 124 byteBuffer.position(Integer.BYTES - bytes.length); 125 byteBuffer.put(bytes).rewind(); 126 return byteBuffer.getInt(); 127 } 128 129 /** 130 * Convert the int to byte array using big endian. 131 */ i32ToByteArray(int n)132 public static byte[] i32ToByteArray(int n) { 133 return ByteBuffer.allocate(Integer.BYTES).order(ByteOrder.BIG_ENDIAN).putInt(n).array(); 134 } 135 136 /** 137 * Convert the int to byte array using little endian. 138 */ i32ToLeByteArray(int n)139 public static byte[] i32ToLeByteArray(int n) { 140 return ByteBuffer.allocate(Integer.BYTES).order(ByteOrder.LITTLE_ENDIAN).putInt(n).array(); 141 } 142 143 /** 144 * Convert the byte array (in Little Endian format) to a long. The input array could be: of 145 * shorter size (eg: 2 bytes, to represent a shortMacAddress). It could also have length of 8 146 * bytes, but have the MSB 6 bytes zeroed out (the 2 LSB bytes contain the MacAddress). 147 */ macAddressByteArrayToLong(byte[] bytes)148 public static long macAddressByteArrayToLong(byte[] bytes) { 149 if (bytes.length == 2) { 150 return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getShort(); 151 } else if (bytes.length == 4) { 152 return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getInt(); 153 } else if (bytes.length == 8) { 154 if (isExtendedMSBZeroedOut(bytes)) { 155 return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getShort(); 156 } else { 157 return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getLong(); 158 } 159 } else { 160 throw new NumberFormatException("Expected length one of (2, 4, 8) but was " 161 + bytes.length); 162 } 163 } 164 165 /** 166 * Convert the byte array that contains a Short MacAddress format (2 bytes long), into an 167 * Extended MacAddress format (8 bytes long), by padding it with 6 MSB zeroed-out bytes. 168 */ convertShortMacAddressBytesToExtended(byte[] bytes)169 public static byte[] convertShortMacAddressBytesToExtended(byte[] bytes) { 170 if (bytes.length == UWB_DEVICE_SHORT_MAC_ADDRESS_LEN) { 171 return ByteBuffer.allocate(UWB_DEVICE_EXT_MAC_ADDRESS_LEN).put(bytes).array(); 172 } else if (bytes.length == UWB_DEVICE_EXT_MAC_ADDRESS_LEN) { 173 return bytes; 174 } else { 175 throw new NumberFormatException("Expected length one of (2, 8) but was " 176 + bytes.length); 177 } 178 } 179 180 // Check if the MSB bytes are zeroed out. isExtendedMSBZeroedOut(byte[] bytes)181 private static boolean isExtendedMSBZeroedOut(byte[] bytes) { 182 for (int i = UWB_DEVICE_SHORT_MAC_ADDRESS_LEN; i < UWB_DEVICE_EXT_MAC_ADDRESS_LEN; i++) { 183 if (bytes[i] != 0) return false; 184 } 185 return true; 186 } DataTypeConversionUtil()187 private DataTypeConversionUtil() {} 188 } 189