1 /* 2 * Copyright 2024 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 17 package com.android.server.ranging.uwb; 18 19 import static com.google.common.collect.ImmutableList.toImmutableList; 20 21 import android.ranging.uwb.UwbAddress; 22 23 import com.android.server.ranging.RangingTechnology; 24 import com.android.server.ranging.RangingUtils.Conversions; 25 import com.android.server.ranging.oob.TechnologyHeader; 26 27 import com.google.auto.value.AutoValue; 28 import com.google.common.collect.ImmutableList; 29 30 import java.nio.ByteBuffer; 31 import java.util.Arrays; 32 33 /** Capability data for UWB sent as part of CapabilityResponseMessage. */ 34 @AutoValue 35 public abstract class UwbOobCapabilities { 36 37 /** Size in bytes of all properties when serialized. */ 38 private static final int EXPECTED_SIZE_BYTES = 20; 39 40 // Size in bytes for each properties for serialization/deserialization. 41 private static final int UWB_ADDRESS_SIZE = 2; 42 private static final int CHANNELS_SIZE = 4; 43 private static final int PREAMBLES_SIZE = 4; 44 private static final int CONFIG_IDS_SIZE = 4; 45 private static final int MIN_INTERVAL_SIZE = 2; 46 private static final int MIN_SLOT_SIZE = 1; 47 private static final int DEVICE_ROLE_SIZE = 1; 48 49 private static final int CHANNELS_SHIFT = 0; 50 private static final int PREAMBLES_SHIFT = 1; 51 private static final int CONFIG_IDS_SHIFT = 0; 52 private static final int DEVICE_ROLE_SHIFT = 1; 53 54 /** Returns the size of the object in bytes when serialized. */ getSize()55 public static int getSize() { 56 return EXPECTED_SIZE_BYTES; 57 } 58 59 /** 60 * Parses the given byte array and returns {@link UwbOobCapabilities} object. Throws {@link 61 * IllegalArgumentException} on invalid input. 62 */ parseBytes(byte[] capabilitiesBytes)63 public static UwbOobCapabilities parseBytes(byte[] capabilitiesBytes) { 64 TechnologyHeader header = TechnologyHeader.parseBytes(capabilitiesBytes); 65 66 if (capabilitiesBytes.length < EXPECTED_SIZE_BYTES) { 67 throw new IllegalArgumentException( 68 String.format( 69 "UwbCapabilities size is %d, expected at least %d", 70 capabilitiesBytes.length, EXPECTED_SIZE_BYTES)); 71 } 72 73 if (capabilitiesBytes.length < header.getSize()) { 74 throw new IllegalArgumentException( 75 String.format( 76 "UwbCapabilities header size field is %d, but the size of the array " 77 + "is %d", 78 header.getSize(), capabilitiesBytes.length)); 79 } 80 81 if (header.getRangingTechnology() != RangingTechnology.UWB) { 82 throw new IllegalArgumentException( 83 String.format( 84 "UwbCapabilities header technology field is %s, expected %s", 85 header.getRangingTechnology(), RangingTechnology.UWB)); 86 } 87 88 int parseCursor = header.getHeaderSize(); 89 90 // Parse UWB Address 91 UwbAddress uwbAddress = 92 UwbAddress.fromBytes( 93 Arrays.copyOfRange(capabilitiesBytes, parseCursor, 94 parseCursor + UWB_ADDRESS_SIZE)); 95 parseCursor += UWB_ADDRESS_SIZE; 96 97 // Parse Supported Channels 98 ImmutableList<Integer> supportedChannels = 99 Conversions.byteArrayToIntList( 100 Arrays.copyOfRange(capabilitiesBytes, parseCursor, 101 parseCursor + CHANNELS_SIZE), 102 CHANNELS_SHIFT); 103 parseCursor += CHANNELS_SIZE; 104 105 // Parse Supported Preamble Indexes 106 ImmutableList<Integer> supportedPreambleIndexes = 107 Conversions.byteArrayToIntList( 108 Arrays.copyOfRange(capabilitiesBytes, parseCursor, 109 parseCursor + PREAMBLES_SIZE), 110 PREAMBLES_SHIFT); 111 parseCursor += PREAMBLES_SIZE; 112 113 // Parse Supported Config Ids 114 ImmutableList<Integer> supportedConfigIds = 115 Conversions.byteArrayToIntList( 116 Arrays.copyOfRange(capabilitiesBytes, parseCursor, 117 parseCursor + CONFIG_IDS_SIZE), 118 CONFIG_IDS_SHIFT); 119 parseCursor += CONFIG_IDS_SIZE; 120 121 // Parse Minimum Ranging Interval Ms 122 int minimumRangingIntervalMs = 123 Conversions.byteArrayToInt( 124 Arrays.copyOfRange(capabilitiesBytes, parseCursor, 125 parseCursor + MIN_INTERVAL_SIZE)); 126 parseCursor += MIN_INTERVAL_SIZE; 127 128 // Parse Minimum Slot Duration Ms 129 int minimumSlotDurationMs = 130 Conversions.byteArrayToInt( 131 Arrays.copyOfRange(capabilitiesBytes, parseCursor, 132 parseCursor + MIN_SLOT_SIZE)); 133 parseCursor += MIN_SLOT_SIZE; 134 135 // Parse Device Role 136 ImmutableList<Integer> deviceRoles = 137 Conversions.byteArrayToIntList( 138 Arrays.copyOfRange(capabilitiesBytes, parseCursor, 139 parseCursor + DEVICE_ROLE_SIZE), 140 DEVICE_ROLE_SHIFT) 141 .stream() 142 .collect(toImmutableList()); 143 parseCursor += DEVICE_ROLE_SIZE; 144 145 return UwbOobCapabilities.builder() 146 .setUwbAddress(uwbAddress) 147 .setSupportedChannels(supportedChannels) 148 .setSupportedConfigIds(supportedConfigIds) 149 .setSupportedPreambleIndexes(supportedPreambleIndexes) 150 .setMinimumRangingIntervalMs(minimumRangingIntervalMs) 151 .setMinimumSlotDurationMs(minimumSlotDurationMs) 152 .setSupportedDeviceRole(deviceRoles) 153 .build(); 154 } 155 156 /** Serializes this {@link UwbOobCapabilities} object to bytes. */ toBytes()157 public final byte[] toBytes() { 158 ByteBuffer byteBuffer = ByteBuffer.allocate(EXPECTED_SIZE_BYTES); 159 byteBuffer 160 .put(RangingTechnology.UWB.toByte()) 161 .put((byte) EXPECTED_SIZE_BYTES) 162 .put(getUwbAddress().getAddressBytes()) 163 .put(Conversions.intListToByteArrayBitmap(getSupportedChannels(), CHANNELS_SIZE, 164 CHANNELS_SHIFT)) 165 .put( 166 Conversions.intListToByteArrayBitmap( 167 getSupportedPreambleIndexes(), PREAMBLES_SIZE, PREAMBLES_SHIFT)) 168 .put( 169 Conversions.intListToByteArrayBitmap( 170 getSupportedConfigIds(), CONFIG_IDS_SIZE, CONFIG_IDS_SHIFT)) 171 .put(Conversions.intToByteArray(getMinimumRangingIntervalMs(), MIN_INTERVAL_SIZE)) 172 .put(Conversions.intToByteArray(getMinimumSlotDurationMs(), MIN_SLOT_SIZE)) 173 .put( 174 Conversions.intListToByteArrayBitmap( 175 getSupportedDeviceRole().stream() 176 .collect(toImmutableList()), 177 DEVICE_ROLE_SIZE, 178 DEVICE_ROLE_SHIFT)); 179 180 return byteBuffer.array(); 181 } 182 183 /** Returns the {@link UwbAddress} of the device. */ getUwbAddress()184 public abstract UwbAddress getUwbAddress(); 185 186 /** Returns a list of supported channels. */ getSupportedChannels()187 public abstract ImmutableList<Integer> getSupportedChannels(); 188 189 /** Returns a list of supported preamble indexes. */ getSupportedPreambleIndexes()190 public abstract ImmutableList<Integer> getSupportedPreambleIndexes(); 191 192 /** Returns a list of supported config Ids. */ getSupportedConfigIds()193 public abstract ImmutableList<Integer> getSupportedConfigIds(); 194 195 /** Returns minimum supported ranging interval in ms. */ getMinimumRangingIntervalMs()196 public abstract int getMinimumRangingIntervalMs(); 197 198 /** Returns minimum supported slot duration in ms. */ getMinimumSlotDurationMs()199 public abstract int getMinimumSlotDurationMs(); 200 201 /** Returns supported device roles. */ getSupportedDeviceRole()202 public abstract ImmutableList<Integer> getSupportedDeviceRole(); 203 204 /** Returns a builder for {@link UwbOobCapabilities}. */ builder()205 public static Builder builder() { 206 return new AutoValue_UwbOobCapabilities.Builder(); 207 } 208 209 /** Builder for {@link UwbOobCapabilities}. */ 210 @AutoValue.Builder 211 public abstract static class Builder { 212 setUwbAddress(UwbAddress uwbAddress)213 public abstract Builder setUwbAddress(UwbAddress uwbAddress); 214 setSupportedChannels(ImmutableList<Integer> supportedChannels)215 public abstract Builder setSupportedChannels(ImmutableList<Integer> supportedChannels); 216 setSupportedPreambleIndexes( ImmutableList<Integer> supportedPreambleIndexes)217 public abstract Builder setSupportedPreambleIndexes( 218 ImmutableList<Integer> supportedPreambleIndexes); 219 setSupportedConfigIds(ImmutableList<Integer> supportedConfigIds)220 public abstract Builder setSupportedConfigIds(ImmutableList<Integer> supportedConfigIds); 221 setMinimumRangingIntervalMs(int minimumRangingIntervalMs)222 public abstract Builder setMinimumRangingIntervalMs(int minimumRangingIntervalMs); 223 setMinimumSlotDurationMs(int minimumSlotDurationMs)224 public abstract Builder setMinimumSlotDurationMs(int minimumSlotDurationMs); 225 setSupportedDeviceRole( ImmutableList<Integer> supportedDeviceRole)226 public abstract Builder setSupportedDeviceRole( 227 ImmutableList<Integer> supportedDeviceRole); 228 build()229 public abstract UwbOobCapabilities build(); 230 } 231 } 232