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 17 package com.android.server.uwb.params; 18 19 import static com.android.server.uwb.config.CapabilityParam.ADS_TWR; 20 import static com.android.server.uwb.config.CapabilityParam.ADVERTISER; 21 import static com.android.server.uwb.config.CapabilityParam.AOA_AZIMUTH_180; 22 import static com.android.server.uwb.config.CapabilityParam.AOA_AZIMUTH_90; 23 import static com.android.server.uwb.config.CapabilityParam.AOA_ELEVATION; 24 import static com.android.server.uwb.config.CapabilityParam.AOA_FOM; 25 import static com.android.server.uwb.config.CapabilityParam.AOA_RESULT_REQ_INTERLEAVING; 26 import static com.android.server.uwb.config.CapabilityParam.BLOCK_BASED_SCHEDULING; 27 import static com.android.server.uwb.config.CapabilityParam.BLOCK_STRIDING; 28 import static com.android.server.uwb.config.CapabilityParam.CC_CONSTRAINT_LENGTH_K3; 29 import static com.android.server.uwb.config.CapabilityParam.CC_CONSTRAINT_LENGTH_K7; 30 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_10; 31 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_12; 32 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_13; 33 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_14; 34 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_5; 35 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_6; 36 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_8; 37 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_9; 38 import static com.android.server.uwb.config.CapabilityParam.CONSTRAINT_LENGTH_3; 39 import static com.android.server.uwb.config.CapabilityParam.CONSTRAINT_LENGTH_7; 40 import static com.android.server.uwb.config.CapabilityParam.CONTENTION_BASED_RANGING; 41 import static com.android.server.uwb.config.CapabilityParam.DIAGNOSTICS; 42 import static com.android.server.uwb.config.CapabilityParam.DS_TWR_DEFERRED; 43 import static com.android.server.uwb.config.CapabilityParam.DS_TWR_NON_DEFERRED; 44 import static com.android.server.uwb.config.CapabilityParam.DT_ANCHOR; 45 import static com.android.server.uwb.config.CapabilityParam.DT_TAG; 46 import static com.android.server.uwb.config.CapabilityParam.DT_TAG_BLOCK_SKIPPING; 47 import static com.android.server.uwb.config.CapabilityParam.DYNAMIC_STS; 48 import static com.android.server.uwb.config.CapabilityParam.DYNAMIC_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY; 49 import static com.android.server.uwb.config.CapabilityParam.ESS_TWR_NON_DEFERRED; 50 import static com.android.server.uwb.config.CapabilityParam.EXTENDED_MAC_ADDRESS; 51 import static com.android.server.uwb.config.CapabilityParam.HOPPING_MODE; 52 import static com.android.server.uwb.config.CapabilityParam.INITIATOR; 53 import static com.android.server.uwb.config.CapabilityParam.INTERVAL_BASED_SCHEDULING; 54 import static com.android.server.uwb.config.CapabilityParam.MANY_TO_MANY; 55 import static com.android.server.uwb.config.CapabilityParam.OBSERVER; 56 import static com.android.server.uwb.config.CapabilityParam.ONE_TO_MANY; 57 import static com.android.server.uwb.config.CapabilityParam.OWR_AOA; 58 import static com.android.server.uwb.config.CapabilityParam.OWR_DL_TDOA; 59 import static com.android.server.uwb.config.CapabilityParam.OWR_UL_TDOA; 60 import static com.android.server.uwb.config.CapabilityParam.PROVISIONED_STS; 61 import static com.android.server.uwb.config.CapabilityParam.PROVISIONED_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY; 62 import static com.android.server.uwb.config.CapabilityParam.PSDU_LENGTH_SUPPORT; 63 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_DISABLE; 64 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE; 65 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_AOA_EDGE_TRIG; 66 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_AOA_LEVEL_TRIG; 67 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_EDGE_TRIG; 68 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_LEVEL_TRIG; 69 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_EDGE_TRIG; 70 import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_LEVEL_TRIG; 71 import static com.android.server.uwb.config.CapabilityParam.RESPONDER; 72 import static com.android.server.uwb.config.CapabilityParam.RSSI_REPORTING; 73 import static com.android.server.uwb.config.CapabilityParam.SP0; 74 import static com.android.server.uwb.config.CapabilityParam.SP1; 75 import static com.android.server.uwb.config.CapabilityParam.SP3; 76 import static com.android.server.uwb.config.CapabilityParam.SS_TWR_DEFERRED; 77 import static com.android.server.uwb.config.CapabilityParam.SS_TWR_NON_DEFERRED; 78 import static com.android.server.uwb.config.CapabilityParam.STATIC_STS; 79 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_AOA_RESULT_REQ_INTERLEAVING; 80 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_AOA_VER_1_0; 81 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_AOA_VER_2_0; 82 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_BLOCK_STRIDING_VER_1_0; 83 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_BLOCK_STRIDING_VER_2_0; 84 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_BPRF_PARAMETER_SETS_VER_1_0; 85 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_BPRF_PARAMETER_SETS_VER_2_0; 86 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_CC_CONSTRAINT_LENGTH_VER_1_0; 87 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_CC_CONSTRAINT_LENGTH_VER_2_0; 88 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_CHANNELS_VER_1_0; 89 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_CHANNELS_VER_2_0; 90 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DEVICE_ROLES_VER_1_0; 91 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DEVICE_ROLES_VER_2_0; 92 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DEVICE_TYPE_VER_2_0; 93 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DIAGNOSTICS; 94 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DT_TAG_BLOCK_SKIPPING_2_0; 95 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DT_TAG_MAX_ACTIVE_RR_2_0; 96 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_EXTENDED_MAC_ADDRESS_VER_1_0; 97 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_EXTENDED_MAC_ADDRESS_VER_2_0; 98 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_FIRA_MAC_VERSION_RANGE_VER_1_0; 99 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_FIRA_MAC_VERSION_RANGE_VER_2_0; 100 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_FIRA_PHY_VERSION_RANGE_VER_1_0; 101 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_FIRA_PHY_VERSION_RANGE_VER_2_0; 102 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_HOPPING_MODE_VER_1_0; 103 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_HOPPING_MODE_VER_2_0; 104 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_HPRF_PARAMETER_SETS_VER_1_0; 105 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_HPRF_PARAMETER_SETS_VER_2_0; 106 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE_VER_1_0; 107 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE_VER_2_0; 108 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MAX_MESSAGE_SIZE_VER_1_0; 109 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MAX_MESSAGE_SIZE_VER_2_0; 110 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MAX_RANGING_SESSION_NUMBER; 111 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MIN_RANGING_INTERVAL_MS; 112 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MIN_SLOT_DURATION_RSTU; 113 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MULTI_NODE_MODES_VER_1_0; 114 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MULTI_NODE_MODES_VER_2_0; 115 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_PSDU_LENGTH_2_0; 116 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGE_DATA_NTF_CONFIG; 117 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGING_METHOD_VER_1_0; 118 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGING_METHOD_VER_2_0; 119 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGING_TIME_STRUCT_VER_1_0; 120 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGING_TIME_STRUCT_VER_2_0; 121 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RFRAME_CONFIG_VER_1_0; 122 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RFRAME_CONFIG_VER_2_0; 123 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RSSI_REPORTING; 124 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_SCHEDULED_MODE_VER_1_0; 125 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_SCHEDULED_MODE_VER_2_0; 126 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_SESSION_KEY_LENGTH_VER_2_0; 127 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_STS_CONFIG_VER_1_0; 128 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_STS_CONFIG_VER_2_0; 129 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_SUSPEND_RANGING_VER_2_0; 130 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_UWB_INITIATION_TIME_VER_1_0; 131 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_UWB_INITIATION_TIME_VER_2_0; 132 import static com.android.server.uwb.config.CapabilityParam.TIME_SCHEDULED_RANGING; 133 import static com.android.server.uwb.config.CapabilityParam.UNICAST; 134 import static com.android.server.uwb.config.CapabilityParam.UT_ANCHOR; 135 import static com.android.server.uwb.config.CapabilityParam.UT_SYNCHRONIZATION_ANCHOR; 136 import static com.android.server.uwb.config.CapabilityParam.UT_TAG; 137 import static com.android.server.uwb.config.CapabilityParam.UWB_INITIATION_TIME; 138 139 import android.util.Log; 140 141 import com.android.server.uwb.UwbInjector; 142 143 import com.google.uwb.support.base.FlagEnum; 144 import com.google.uwb.support.base.Params; 145 import com.google.uwb.support.base.ProtocolVersion; 146 import com.google.uwb.support.fira.FiraParams; 147 import com.google.uwb.support.fira.FiraParams.BprfParameterSetCapabilityFlag; 148 import com.google.uwb.support.fira.FiraParams.CcConstraintLengthCapabilitiesFlag; 149 import com.google.uwb.support.fira.FiraParams.DeviceRoleCapabilityFlag; 150 import com.google.uwb.support.fira.FiraParams.HprfParameterSetCapabilityFlag; 151 import com.google.uwb.support.fira.FiraParams.MultiNodeCapabilityFlag; 152 import com.google.uwb.support.fira.FiraParams.PsduDataRateCapabilityFlag; 153 import com.google.uwb.support.fira.FiraParams.RangingRoundCapabilityFlag; 154 import com.google.uwb.support.fira.FiraParams.RangingTimeStructCapabilitiesFlag; 155 import com.google.uwb.support.fira.FiraParams.RframeCapabilityFlag; 156 import com.google.uwb.support.fira.FiraParams.SchedulingModeCapabilitiesFlag; 157 import com.google.uwb.support.fira.FiraParams.StsCapabilityFlag; 158 import com.google.uwb.support.fira.FiraProtocolVersion; 159 import com.google.uwb.support.fira.FiraSpecificationParams; 160 161 import java.math.BigInteger; 162 import java.util.ArrayList; 163 import java.util.EnumSet; 164 import java.util.List; 165 import java.util.stream.IntStream; 166 167 public class FiraDecoder extends TlvDecoder { 168 private static final String TAG = "FiraDecoder"; 169 170 private final UwbInjector mUwbInjector; 171 FiraDecoder(UwbInjector uwbInjector)172 public FiraDecoder(UwbInjector uwbInjector) { 173 mUwbInjector = uwbInjector; 174 } 175 176 @Override getParams(TlvDecoderBuffer tlvs, Class<T> paramType, ProtocolVersion protocolVersion)177 public <T extends Params> T getParams(TlvDecoderBuffer tlvs, Class<T> paramType, 178 ProtocolVersion protocolVersion) { 179 if (FiraSpecificationParams.class.equals(paramType)) { 180 // The "protocolVersion" is always expected to be of type "FiraProtocolVersion" here, 181 // but in case it's not, we use a backup value of "PROTOCOL_VERSION_1_1". 182 FiraProtocolVersion uwbsFiraProtocolVersion = 183 (protocolVersion instanceof FiraProtocolVersion) 184 ? (FiraProtocolVersion) protocolVersion : FiraParams.PROTOCOL_VERSION_1_1; 185 return (T) getFiraSpecificationParamsFromTlvBuffer(tlvs, uwbsFiraProtocolVersion); 186 } 187 return null; 188 } 189 isBitSet(int flags, int mask)190 private static boolean isBitSet(int flags, int mask) { 191 return (flags & mask) != 0; 192 } 193 getFiraSpecificationParamsFromTlvBuffer(TlvDecoderBuffer tlvs, ProtocolVersion protocolVersion)194 private FiraSpecificationParams getFiraSpecificationParamsFromTlvBuffer(TlvDecoderBuffer tlvs, 195 ProtocolVersion protocolVersion) { 196 FiraSpecificationParams.Builder builder = new FiraSpecificationParams.Builder(); 197 byte[] versionCheck = tlvs.getByteArray(SUPPORTED_FIRA_PHY_VERSION_RANGE_VER_2_0); 198 if (versionCheck.length == 1) { 199 // FiRa Version 1.0 200 byte[] phyVersions = tlvs.getByteArray(SUPPORTED_FIRA_PHY_VERSION_RANGE_VER_1_0); 201 builder.setMinPhyVersionSupported(FiraProtocolVersion.fromBytes(phyVersions, 0)); 202 builder.setMaxPhyVersionSupported(FiraProtocolVersion.fromBytes(phyVersions, 2)); 203 byte[] macVersions = tlvs.getByteArray(SUPPORTED_FIRA_MAC_VERSION_RANGE_VER_1_0); 204 builder.setMinMacVersionSupported(FiraProtocolVersion.fromBytes(macVersions, 0)); 205 builder.setMaxMacVersionSupported(FiraProtocolVersion.fromBytes(macVersions, 2)); 206 207 byte deviceRolesUci = tlvs.getByte(SUPPORTED_DEVICE_ROLES_VER_1_0); 208 EnumSet<DeviceRoleCapabilityFlag> deviceRoles = 209 EnumSet.noneOf(DeviceRoleCapabilityFlag.class); 210 if (isBitSet(deviceRolesUci, INITIATOR)) { 211 // This assumes both controller + controlee is supported. 212 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLLER_INITIATOR_SUPPORT); 213 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLEE_INITIATOR_SUPPORT); 214 } 215 if (isBitSet(deviceRolesUci, RESPONDER)) { 216 // This assumes both controller + controlee is supported. 217 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLLER_RESPONDER_SUPPORT); 218 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLEE_RESPONDER_SUPPORT); 219 } 220 builder.setDeviceRoleCapabilities(deviceRoles); 221 222 byte rangingMethodUci = tlvs.getByte(SUPPORTED_RANGING_METHOD_VER_1_0); 223 EnumSet<RangingRoundCapabilityFlag> rangingRoundFlag = EnumSet.noneOf( 224 RangingRoundCapabilityFlag.class); 225 if (isBitSet(rangingMethodUci, DS_TWR_DEFERRED)) { 226 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_DS_TWR_SUPPORT); 227 } 228 if (isBitSet(rangingMethodUci, SS_TWR_DEFERRED)) { 229 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_SS_TWR_SUPPORT); 230 } 231 builder.setRangingRoundCapabilities(rangingRoundFlag); 232 233 // TODO(b/209053358): This does not align with UCI spec. 234 if (isBitSet(rangingMethodUci, DS_TWR_NON_DEFERRED) 235 || isBitSet(rangingMethodUci, SS_TWR_NON_DEFERRED)) { 236 builder.hasNonDeferredModeSupport(true); 237 } 238 239 byte stsConfigUci = tlvs.getByte(SUPPORTED_STS_CONFIG_VER_1_0); 240 EnumSet<StsCapabilityFlag> stsCapabilityFlag = EnumSet.noneOf(StsCapabilityFlag.class); 241 if (isBitSet(stsConfigUci, STATIC_STS)) { 242 stsCapabilityFlag.add(StsCapabilityFlag.HAS_STATIC_STS_SUPPORT); 243 } 244 if (isBitSet(stsConfigUci, DYNAMIC_STS)) { 245 stsCapabilityFlag.add(StsCapabilityFlag.HAS_DYNAMIC_STS_SUPPORT); 246 } 247 if (isBitSet(stsConfigUci, DYNAMIC_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY)) { 248 stsCapabilityFlag.add( 249 StsCapabilityFlag.HAS_DYNAMIC_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT); 250 } 251 if (isBitSet(stsConfigUci, PROVISIONED_STS)) { 252 stsCapabilityFlag.add(StsCapabilityFlag.HAS_PROVISIONED_STS_SUPPORT); 253 } 254 if (isBitSet(stsConfigUci, PROVISIONED_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY)) { 255 stsCapabilityFlag.add( 256 StsCapabilityFlag.HAS_PROVISIONED_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT); 257 } 258 builder.setStsCapabilities(stsCapabilityFlag); 259 260 byte multiNodeUci = tlvs.getByte(SUPPORTED_MULTI_NODE_MODES_VER_1_0); 261 EnumSet<MultiNodeCapabilityFlag> multiNodeFlag = 262 EnumSet.noneOf(MultiNodeCapabilityFlag.class); 263 if (isBitSet(multiNodeUci, UNICAST)) { 264 multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_UNICAST_SUPPORT); 265 } 266 if (isBitSet(multiNodeUci, ONE_TO_MANY)) { 267 multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_ONE_TO_MANY_SUPPORT); 268 } 269 if (isBitSet(multiNodeUci, MANY_TO_MANY)) { 270 multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_MANY_TO_MANY_SUPPORT); 271 } 272 builder.setMultiNodeCapabilities(multiNodeFlag); 273 274 byte rangingTimeStructUci = tlvs.getByte(SUPPORTED_RANGING_TIME_STRUCT_VER_1_0); 275 EnumSet<RangingTimeStructCapabilitiesFlag> rangingTimeStructFlag = 276 EnumSet.noneOf(RangingTimeStructCapabilitiesFlag.class); 277 if (protocolVersion.getMajor() <= 2 278 && isBitSet(rangingTimeStructUci, INTERVAL_BASED_SCHEDULING)) { 279 rangingTimeStructFlag.add( 280 RangingTimeStructCapabilitiesFlag.HAS_INTERVAL_BASED_SCHEDULING_SUPPORT); 281 } 282 if (isBitSet(rangingTimeStructUci, BLOCK_BASED_SCHEDULING)) { 283 rangingTimeStructFlag.add( 284 RangingTimeStructCapabilitiesFlag.HAS_BLOCK_BASED_SCHEDULING_SUPPORT); 285 } 286 builder.setRangingTimeStructCapabilities(rangingTimeStructFlag); 287 288 byte schedulingModeUci = tlvs.getByte(SUPPORTED_SCHEDULED_MODE_VER_1_0); 289 EnumSet<SchedulingModeCapabilitiesFlag> schedulingModeFlag = 290 EnumSet.noneOf(SchedulingModeCapabilitiesFlag.class); 291 if (isBitSet(schedulingModeUci, CONTENTION_BASED_RANGING)) { 292 schedulingModeFlag.add( 293 SchedulingModeCapabilitiesFlag.HAS_CONTENTION_BASED_RANGING_SUPPORT); 294 } 295 if (isBitSet(schedulingModeUci, TIME_SCHEDULED_RANGING)) { 296 schedulingModeFlag.add( 297 SchedulingModeCapabilitiesFlag.HAS_TIME_SCHEDULED_RANGING_SUPPORT); 298 } 299 builder.setSchedulingModeCapabilities(schedulingModeFlag); 300 301 byte ccConstraintLengthUci = tlvs.getByte(SUPPORTED_CC_CONSTRAINT_LENGTH_VER_1_0); 302 EnumSet<CcConstraintLengthCapabilitiesFlag> ccConstraintLengthFlag = 303 EnumSet.noneOf(CcConstraintLengthCapabilitiesFlag.class); 304 if (isBitSet(ccConstraintLengthUci, CONSTRAINT_LENGTH_3)) { 305 ccConstraintLengthFlag.add( 306 CcConstraintLengthCapabilitiesFlag.HAS_CONSTRAINT_LENGTH_3_SUPPORT); 307 } 308 if (isBitSet(ccConstraintLengthUci, CONSTRAINT_LENGTH_7)) { 309 ccConstraintLengthFlag.add( 310 CcConstraintLengthCapabilitiesFlag.HAS_CONSTRAINT_LENGTH_7_SUPPORT); 311 } 312 builder.setCcConstraintLengthCapabilities(ccConstraintLengthFlag); 313 314 byte blockStridingUci = tlvs.getByte(SUPPORTED_BLOCK_STRIDING_VER_1_0); 315 if (isBitSet(blockStridingUci, BLOCK_STRIDING)) { 316 builder.hasBlockStridingSupport(true); 317 } 318 319 byte hoppingPreferenceUci = tlvs.getByte(SUPPORTED_HOPPING_MODE_VER_1_0); 320 if (isBitSet(hoppingPreferenceUci, HOPPING_MODE)) { 321 builder.hasHoppingPreferenceSupport(true); 322 } 323 324 byte extendedMacAddressUci = tlvs.getByte(SUPPORTED_EXTENDED_MAC_ADDRESS_VER_1_0); 325 if (isBitSet(extendedMacAddressUci, EXTENDED_MAC_ADDRESS)) { 326 builder.hasExtendedMacAddressSupport(true); 327 } 328 329 byte initiationTimeUci = tlvs.getByte(SUPPORTED_UWB_INITIATION_TIME_VER_1_0); 330 if (isBitSet(initiationTimeUci, UWB_INITIATION_TIME)) { 331 builder.hasInitiationTimeSupport(true); 332 } 333 334 byte channelsUci = tlvs.getByte(SUPPORTED_CHANNELS_VER_1_0); 335 List<Integer> channels = new ArrayList<>(); 336 if (isBitSet(channelsUci, CHANNEL_5)) { 337 channels.add(5); 338 } 339 if (isBitSet(channelsUci, CHANNEL_6)) { 340 channels.add(6); 341 } 342 if (isBitSet(channelsUci, CHANNEL_8)) { 343 channels.add(8); 344 } 345 if (isBitSet(channelsUci, CHANNEL_9)) { 346 channels.add(9); 347 } 348 if (isBitSet(channelsUci, CHANNEL_10)) { 349 channels.add(10); 350 } 351 if (isBitSet(channelsUci, CHANNEL_12)) { 352 channels.add(12); 353 } 354 if (isBitSet(channelsUci, CHANNEL_13)) { 355 channels.add(13); 356 } 357 if (isBitSet(channelsUci, CHANNEL_14)) { 358 channels.add(14); 359 } 360 builder.setSupportedChannels(channels); 361 362 byte rframeConfigUci = tlvs.getByte(SUPPORTED_RFRAME_CONFIG_VER_1_0); 363 EnumSet<RframeCapabilityFlag> rframeConfigFlag = 364 EnumSet.noneOf(RframeCapabilityFlag.class); 365 if (isBitSet(rframeConfigUci, SP0)) { 366 rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP0_RFRAME_SUPPORT); 367 } 368 if (isBitSet(rframeConfigUci, SP1)) { 369 rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP1_RFRAME_SUPPORT); 370 } 371 if (isBitSet(rframeConfigUci, SP3)) { 372 rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP3_RFRAME_SUPPORT); 373 } 374 builder.setRframeCapabilities(rframeConfigFlag); 375 376 byte bprfSets = tlvs.getByte(SUPPORTED_BPRF_PARAMETER_SETS_VER_1_0); 377 int bprfSetsValue = Integer.valueOf(bprfSets); 378 EnumSet<BprfParameterSetCapabilityFlag> bprfFlag; 379 bprfFlag = FlagEnum.toEnumSet(bprfSetsValue, BprfParameterSetCapabilityFlag.values()); 380 builder.setBprfParameterSetCapabilities(bprfFlag); 381 382 byte[] hprfSets = tlvs.getByteArray(SUPPORTED_HPRF_PARAMETER_SETS_VER_1_0); 383 // Extend the 5 bytes from HAL to 8 bytes for long. 384 long hprfSetsValue = new BigInteger(TlvUtil.getReverseBytes(hprfSets)).longValue(); 385 EnumSet<HprfParameterSetCapabilityFlag> hprfFlag; 386 hprfFlag = FlagEnum.longToEnumSet( 387 hprfSetsValue, HprfParameterSetCapabilityFlag.values()); 388 builder.setHprfParameterSetCapabilities(hprfFlag); 389 390 EnumSet<FiraParams.PrfCapabilityFlag> prfFlag = 391 EnumSet.noneOf(FiraParams.PrfCapabilityFlag.class); 392 boolean hasBprfSupport = bprfSets != 0; 393 if (hasBprfSupport) { 394 prfFlag.add(FiraParams.PrfCapabilityFlag.HAS_BPRF_SUPPORT); 395 } 396 boolean hasHprfSupport = 397 IntStream.range(0, hprfSets.length).parallel().anyMatch(i -> hprfSets[i] != 0); 398 if (hasHprfSupport) { 399 prfFlag.add(FiraParams.PrfCapabilityFlag.HAS_HPRF_SUPPORT); 400 } 401 builder.setPrfCapabilities(prfFlag); 402 403 byte ccConstraintUci = tlvs.getByte(SUPPORTED_CC_CONSTRAINT_LENGTH_VER_1_0); 404 EnumSet<PsduDataRateCapabilityFlag> psduRateFlag = 405 EnumSet.noneOf(PsduDataRateCapabilityFlag.class); 406 if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K3) && hasBprfSupport) { 407 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_6M81_SUPPORT); 408 } 409 if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K7) && hasBprfSupport) { 410 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_7M80_SUPPORT); 411 } 412 if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K3) && hasHprfSupport) { 413 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_27M2_SUPPORT); 414 } 415 if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K7) && hasHprfSupport) { 416 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_31M2_SUPPORT); 417 } 418 builder.setPsduDataRateCapabilities(psduRateFlag); 419 420 byte aoaUci = tlvs.getByte(SUPPORTED_AOA_VER_1_0); 421 EnumSet<FiraParams.AoaCapabilityFlag> aoaFlag = 422 EnumSet.noneOf(FiraParams.AoaCapabilityFlag.class); 423 if (isBitSet(aoaUci, AOA_AZIMUTH_90)) { 424 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_AZIMUTH_SUPPORT); 425 } 426 if (isBitSet(aoaUci, AOA_AZIMUTH_180)) { 427 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_FULL_AZIMUTH_SUPPORT); 428 } 429 if (isBitSet(aoaUci, AOA_ELEVATION)) { 430 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_ELEVATION_SUPPORT); 431 } 432 if (isBitSet(aoaUci, AOA_FOM)) { 433 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_FOM_SUPPORT); 434 } 435 byte aoaInterleavingUci = tlvs.getByte(SUPPORTED_AOA_RESULT_REQ_INTERLEAVING); 436 if (isBitSet(aoaInterleavingUci, AOA_RESULT_REQ_INTERLEAVING)) { 437 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_INTERLEAVING_SUPPORT); 438 } 439 builder.setAoaCapabilities(aoaFlag); 440 441 try { 442 int maxMessageSizeUci = tlvs.getShort(SUPPORTED_MAX_MESSAGE_SIZE_VER_1_0); 443 builder.setMaxMessageSize(Integer.valueOf(maxMessageSizeUci)); 444 } catch (IllegalArgumentException e) { 445 Log.w(TAG, "SUPPORTED_MAX_MESSAGE_SIZE not found."); 446 } 447 try { 448 int maxDataPacketPayloadSizeUci = tlvs.getShort( 449 SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE_VER_1_0); 450 builder.setMaxDataPacketPayloadSize(Integer.valueOf(maxDataPacketPayloadSizeUci)); 451 } catch (IllegalArgumentException e) { 452 Log.w(TAG, "SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE not found."); 453 } 454 } else if (versionCheck.length == 4) { 455 // FiRa Version 2.0 456 byte[] phyVersions = tlvs.getByteArray(SUPPORTED_FIRA_PHY_VERSION_RANGE_VER_2_0); 457 builder.setMinPhyVersionSupported(FiraProtocolVersion.fromBytes(phyVersions, 0)); 458 builder.setMaxPhyVersionSupported(FiraProtocolVersion.fromBytes(phyVersions, 2)); 459 byte[] macVersions = tlvs.getByteArray(SUPPORTED_FIRA_MAC_VERSION_RANGE_VER_2_0); 460 builder.setMinMacVersionSupported(FiraProtocolVersion.fromBytes(macVersions, 0)); 461 builder.setMaxMacVersionSupported(FiraProtocolVersion.fromBytes(macVersions, 2)); 462 463 byte[] deviceRolesUci = tlvs.getByteArray(SUPPORTED_DEVICE_ROLES_VER_2_0); 464 EnumSet<DeviceRoleCapabilityFlag> deviceRoles = 465 EnumSet.noneOf(DeviceRoleCapabilityFlag.class); 466 if (isBitSet(deviceRolesUci[0], INITIATOR)) { 467 // This assumes both controller + controlee is supported. 468 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLLER_INITIATOR_SUPPORT); 469 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLEE_INITIATOR_SUPPORT); 470 } 471 if (isBitSet(deviceRolesUci[0], RESPONDER)) { 472 // This assumes both controller + controlee is supported. 473 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLLER_RESPONDER_SUPPORT); 474 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLEE_RESPONDER_SUPPORT); 475 } 476 if (isBitSet(deviceRolesUci[0], UT_SYNCHRONIZATION_ANCHOR)) { 477 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_UT_SYNCHRONIZATION_SUPPORT); 478 } 479 if (isBitSet(deviceRolesUci[0], UT_ANCHOR)) { 480 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_UT_ANCHOR_SUPPORT); 481 } 482 if (isBitSet(deviceRolesUci[0], UT_TAG)) { 483 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_UT_TAG_SUPPORT); 484 } 485 if (isBitSet(deviceRolesUci[0], ADVERTISER)) { 486 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_ADVERTISER_SUPPORT); 487 } 488 if (isBitSet(deviceRolesUci[0], OBSERVER)) { 489 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_OBSERVER_SUPPORT); 490 } 491 if (isBitSet(deviceRolesUci[0], DT_ANCHOR)) { 492 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_DT_ANCHOR_SUPPORT); 493 } 494 if (isBitSet(deviceRolesUci[1], DT_TAG)) { 495 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_DT_TAG_SUPPORT); 496 } 497 builder.setDeviceRoleCapabilities(deviceRoles); 498 499 byte[] rangingMethodUci = tlvs.getByteArray(SUPPORTED_RANGING_METHOD_VER_2_0); 500 EnumSet<RangingRoundCapabilityFlag> rangingRoundFlag = EnumSet.noneOf( 501 RangingRoundCapabilityFlag.class); 502 if (isBitSet(rangingMethodUci[0], DS_TWR_DEFERRED)) { 503 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_DS_TWR_SUPPORT); 504 } 505 if (isBitSet(rangingMethodUci[0], SS_TWR_DEFERRED)) { 506 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_SS_TWR_SUPPORT); 507 } 508 if (isBitSet(rangingMethodUci[0], OWR_UL_TDOA)) { 509 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_OWR_UL_TDOA_SUPPORT); 510 } 511 if (isBitSet(rangingMethodUci[0], OWR_DL_TDOA)) { 512 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_OWR_DL_TDOA_SUPPORT); 513 } 514 if (isBitSet(rangingMethodUci[0], OWR_AOA)) { 515 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_OWR_AOA_SUPPORT); 516 } 517 if (isBitSet(rangingMethodUci[0], ESS_TWR_NON_DEFERRED)) { 518 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_ESS_TWR_SUPPORT); 519 } 520 if (isBitSet(rangingMethodUci[1], ADS_TWR)) { 521 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_ADS_TWR_SUPPORT); 522 } 523 builder.setRangingRoundCapabilities(rangingRoundFlag); 524 525 // TODO(b/209053358): This does not align with UCI spec. 526 if (isBitSet(rangingMethodUci[0], DS_TWR_NON_DEFERRED) 527 || isBitSet(rangingMethodUci[0], SS_TWR_NON_DEFERRED)) { 528 builder.hasNonDeferredModeSupport(true); 529 } 530 531 byte stsConfigUci = tlvs.getByte(SUPPORTED_STS_CONFIG_VER_2_0); 532 EnumSet<StsCapabilityFlag> stsCapabilityFlag = EnumSet.noneOf(StsCapabilityFlag.class); 533 if (isBitSet(stsConfigUci, STATIC_STS)) { 534 stsCapabilityFlag.add(StsCapabilityFlag.HAS_STATIC_STS_SUPPORT); 535 } 536 if (isBitSet(stsConfigUci, DYNAMIC_STS)) { 537 stsCapabilityFlag.add(StsCapabilityFlag.HAS_DYNAMIC_STS_SUPPORT); 538 } 539 if (isBitSet(stsConfigUci, DYNAMIC_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY)) { 540 stsCapabilityFlag.add( 541 StsCapabilityFlag.HAS_DYNAMIC_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT); 542 } 543 if (isBitSet(stsConfigUci, PROVISIONED_STS)) { 544 stsCapabilityFlag.add(StsCapabilityFlag.HAS_PROVISIONED_STS_SUPPORT); 545 } 546 if (isBitSet(stsConfigUci, PROVISIONED_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY)) { 547 stsCapabilityFlag.add( 548 StsCapabilityFlag.HAS_PROVISIONED_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT); 549 } 550 builder.setStsCapabilities(stsCapabilityFlag); 551 552 byte multiNodeUci = tlvs.getByte(SUPPORTED_MULTI_NODE_MODES_VER_2_0); 553 EnumSet<MultiNodeCapabilityFlag> multiNodeFlag = 554 EnumSet.noneOf(MultiNodeCapabilityFlag.class); 555 if (isBitSet(multiNodeUci, UNICAST)) { 556 multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_UNICAST_SUPPORT); 557 } 558 if (isBitSet(multiNodeUci, ONE_TO_MANY)) { 559 multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_ONE_TO_MANY_SUPPORT); 560 } 561 if (isBitSet(multiNodeUci, MANY_TO_MANY)) { 562 multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_MANY_TO_MANY_SUPPORT); 563 } 564 builder.setMultiNodeCapabilities(multiNodeFlag); 565 566 byte rangingTimeStructUci = tlvs.getByte(SUPPORTED_RANGING_TIME_STRUCT_VER_2_0); 567 EnumSet<RangingTimeStructCapabilitiesFlag> rangingTimeStructFlag = 568 EnumSet.noneOf(RangingTimeStructCapabilitiesFlag.class); 569 if (isBitSet(rangingTimeStructUci, BLOCK_BASED_SCHEDULING)) { 570 rangingTimeStructFlag.add( 571 RangingTimeStructCapabilitiesFlag.HAS_BLOCK_BASED_SCHEDULING_SUPPORT); 572 } 573 builder.setRangingTimeStructCapabilities(rangingTimeStructFlag); 574 575 byte schedulingModeUci = tlvs.getByte(SUPPORTED_SCHEDULED_MODE_VER_2_0); 576 EnumSet<SchedulingModeCapabilitiesFlag> schedulingModeFlag = 577 EnumSet.noneOf(SchedulingModeCapabilitiesFlag.class); 578 if (isBitSet(schedulingModeUci, CONTENTION_BASED_RANGING)) { 579 schedulingModeFlag.add( 580 SchedulingModeCapabilitiesFlag.HAS_CONTENTION_BASED_RANGING_SUPPORT); 581 } 582 if (isBitSet(schedulingModeUci, TIME_SCHEDULED_RANGING)) { 583 schedulingModeFlag.add( 584 SchedulingModeCapabilitiesFlag.HAS_TIME_SCHEDULED_RANGING_SUPPORT); 585 } 586 builder.setSchedulingModeCapabilities(schedulingModeFlag); 587 588 byte ccConstraintLengthUci = tlvs.getByte(SUPPORTED_CC_CONSTRAINT_LENGTH_VER_2_0); 589 EnumSet<CcConstraintLengthCapabilitiesFlag> ccConstraintLengthFlag = 590 EnumSet.noneOf(CcConstraintLengthCapabilitiesFlag.class); 591 if (isBitSet(ccConstraintLengthUci, CONSTRAINT_LENGTH_3)) { 592 ccConstraintLengthFlag.add( 593 CcConstraintLengthCapabilitiesFlag.HAS_CONSTRAINT_LENGTH_3_SUPPORT); 594 } 595 if (isBitSet(ccConstraintLengthUci, CONSTRAINT_LENGTH_7)) { 596 ccConstraintLengthFlag.add( 597 CcConstraintLengthCapabilitiesFlag.HAS_CONSTRAINT_LENGTH_7_SUPPORT); 598 } 599 builder.setCcConstraintLengthCapabilities(ccConstraintLengthFlag); 600 601 byte blockStridingUci = tlvs.getByte(SUPPORTED_BLOCK_STRIDING_VER_2_0); 602 if (isBitSet(blockStridingUci, BLOCK_STRIDING)) { 603 builder.hasBlockStridingSupport(true); 604 } 605 606 byte hoppingPreferenceUci = tlvs.getByte(SUPPORTED_HOPPING_MODE_VER_2_0); 607 if (isBitSet(hoppingPreferenceUci, HOPPING_MODE)) { 608 builder.hasHoppingPreferenceSupport(true); 609 } 610 611 byte extendedMacAddressUci = tlvs.getByte(SUPPORTED_EXTENDED_MAC_ADDRESS_VER_2_0); 612 if (isBitSet(extendedMacAddressUci, EXTENDED_MAC_ADDRESS)) { 613 builder.hasExtendedMacAddressSupport(true); 614 } 615 616 byte initiationTimeUci = tlvs.getByte(SUPPORTED_UWB_INITIATION_TIME_VER_2_0); 617 if (isBitSet(initiationTimeUci, UWB_INITIATION_TIME)) { 618 builder.hasInitiationTimeSupport(true); 619 } 620 621 byte channelsUci = tlvs.getByte(SUPPORTED_CHANNELS_VER_2_0); 622 List<Integer> channels = new ArrayList<>(); 623 if (isBitSet(channelsUci, CHANNEL_5)) { 624 channels.add(5); 625 } 626 if (isBitSet(channelsUci, CHANNEL_6)) { 627 channels.add(6); 628 } 629 if (isBitSet(channelsUci, CHANNEL_8)) { 630 channels.add(8); 631 } 632 if (isBitSet(channelsUci, CHANNEL_9)) { 633 channels.add(9); 634 } 635 if (isBitSet(channelsUci, CHANNEL_10)) { 636 channels.add(10); 637 } 638 if (isBitSet(channelsUci, CHANNEL_12)) { 639 channels.add(12); 640 } 641 if (isBitSet(channelsUci, CHANNEL_13)) { 642 channels.add(13); 643 } 644 if (isBitSet(channelsUci, CHANNEL_14)) { 645 channels.add(14); 646 } 647 builder.setSupportedChannels(channels); 648 649 byte rframeConfigUci = tlvs.getByte(SUPPORTED_RFRAME_CONFIG_VER_2_0); 650 EnumSet<RframeCapabilityFlag> rframeConfigFlag = 651 EnumSet.noneOf(RframeCapabilityFlag.class); 652 if (isBitSet(rframeConfigUci, SP0)) { 653 rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP0_RFRAME_SUPPORT); 654 } 655 if (isBitSet(rframeConfigUci, SP1)) { 656 rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP1_RFRAME_SUPPORT); 657 } 658 if (isBitSet(rframeConfigUci, SP3)) { 659 rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP3_RFRAME_SUPPORT); 660 } 661 builder.setRframeCapabilities(rframeConfigFlag); 662 663 byte bprfSets = tlvs.getByte(SUPPORTED_BPRF_PARAMETER_SETS_VER_2_0); 664 int bprfSetsValue = Integer.valueOf(bprfSets); 665 EnumSet<BprfParameterSetCapabilityFlag> bprfFlag; 666 bprfFlag = FlagEnum.toEnumSet(bprfSetsValue, BprfParameterSetCapabilityFlag.values()); 667 builder.setBprfParameterSetCapabilities(bprfFlag); 668 669 byte[] hprfSets = tlvs.getByteArray(SUPPORTED_HPRF_PARAMETER_SETS_VER_2_0); 670 // Extend the 5 bytes from HAL to 8 bytes for long. 671 long hprfSetsValue = new BigInteger(TlvUtil.getReverseBytes(hprfSets)).longValue(); 672 EnumSet<HprfParameterSetCapabilityFlag> hprfFlag; 673 hprfFlag = FlagEnum.longToEnumSet( 674 hprfSetsValue, HprfParameterSetCapabilityFlag.values()); 675 builder.setHprfParameterSetCapabilities(hprfFlag); 676 677 EnumSet<FiraParams.PrfCapabilityFlag> prfFlag = 678 EnumSet.noneOf(FiraParams.PrfCapabilityFlag.class); 679 boolean hasBprfSupport = bprfSets != 0; 680 if (hasBprfSupport) { 681 prfFlag.add(FiraParams.PrfCapabilityFlag.HAS_BPRF_SUPPORT); 682 } 683 boolean hasHprfSupport = 684 IntStream.range(0, hprfSets.length).parallel().anyMatch(i -> hprfSets[i] != 0); 685 if (hasHprfSupport) { 686 prfFlag.add(FiraParams.PrfCapabilityFlag.HAS_HPRF_SUPPORT); 687 } 688 builder.setPrfCapabilities(prfFlag); 689 690 byte ccConstraintUci = tlvs.getByte(SUPPORTED_CC_CONSTRAINT_LENGTH_VER_2_0); 691 EnumSet<PsduDataRateCapabilityFlag> psduRateFlag = 692 EnumSet.noneOf(PsduDataRateCapabilityFlag.class); 693 if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K3) && hasBprfSupport) { 694 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_6M81_SUPPORT); 695 } 696 if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K7) && hasBprfSupport) { 697 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_7M80_SUPPORT); 698 } 699 if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K3) && hasHprfSupport) { 700 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_27M2_SUPPORT); 701 } 702 if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K7) && hasHprfSupport) { 703 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_31M2_SUPPORT); 704 } 705 builder.setPsduDataRateCapabilities(psduRateFlag); 706 707 byte aoaUci = tlvs.getByte(SUPPORTED_AOA_VER_2_0); 708 EnumSet<FiraParams.AoaCapabilityFlag> aoaFlag = 709 EnumSet.noneOf(FiraParams.AoaCapabilityFlag.class); 710 if (isBitSet(aoaUci, AOA_AZIMUTH_90)) { 711 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_AZIMUTH_SUPPORT); 712 } 713 if (isBitSet(aoaUci, AOA_AZIMUTH_180)) { 714 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_FULL_AZIMUTH_SUPPORT); 715 } 716 if (isBitSet(aoaUci, AOA_ELEVATION)) { 717 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_ELEVATION_SUPPORT); 718 } 719 if (isBitSet(aoaUci, AOA_FOM)) { 720 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_FOM_SUPPORT); 721 } 722 byte aoaInterleavingUci = tlvs.getByte(SUPPORTED_AOA_RESULT_REQ_INTERLEAVING); 723 if (isBitSet(aoaInterleavingUci, AOA_RESULT_REQ_INTERLEAVING)) { 724 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_INTERLEAVING_SUPPORT); 725 } 726 builder.setAoaCapabilities(aoaFlag); 727 728 try { 729 int maxMessageSizeUci = tlvs.getShort(SUPPORTED_MAX_MESSAGE_SIZE_VER_2_0); 730 builder.setMaxMessageSize(Integer.valueOf(maxMessageSizeUci)); 731 } catch (IllegalArgumentException e) { 732 Log.w(TAG, "SUPPORTED_MAX_MESSAGE_SIZE not found."); 733 } 734 try { 735 int maxDataPacketPayloadSizeUci = tlvs.getShort( 736 SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE_VER_2_0); 737 builder.setMaxDataPacketPayloadSize(Integer.valueOf(maxDataPacketPayloadSizeUci)); 738 } catch (IllegalArgumentException e) { 739 Log.w(TAG, "SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE not found."); 740 } 741 742 int deviceType = tlvs.getByte(SUPPORTED_DEVICE_TYPE_VER_2_0); 743 builder.setDeviceType(deviceType); 744 745 int supportedSuspendSupport = tlvs.getByte(SUPPORTED_SUSPEND_RANGING_VER_2_0); 746 builder.setSuspendRangingSupport(supportedSuspendSupport != 0); 747 748 int sessionKeyLength = tlvs.getByte(SUPPORTED_SESSION_KEY_LENGTH_VER_2_0); 749 builder.setSessionKeyLength(sessionKeyLength); 750 751 try { 752 int dtTagMaxActiveRr = tlvs.getByte(SUPPORTED_DT_TAG_MAX_ACTIVE_RR_2_0); 753 builder.setDtTagMaxActiveRr(dtTagMaxActiveRr); 754 } catch (IllegalArgumentException e) { 755 Log.w(TAG, "SUPPORTED_DT_TAG_MAX_ACTIVE_RR not found."); 756 } 757 758 try { 759 byte dtTagBlockSkippingUci = tlvs.getByte(SUPPORTED_DT_TAG_BLOCK_SKIPPING_2_0); 760 if (isBitSet(dtTagBlockSkippingUci, DT_TAG_BLOCK_SKIPPING)) { 761 builder.setDtTagBlockSkippingSupport(true); 762 } 763 } catch (IllegalArgumentException e) { 764 Log.w(TAG, "SUPPORTED_DT_TAG_BLOCK_SKIPPING_2_0 not found."); 765 } 766 767 try { 768 byte psduLengthUci = tlvs.getByte(SUPPORTED_PSDU_LENGTH_2_0); 769 if (isBitSet(psduLengthUci, PSDU_LENGTH_SUPPORT)) { 770 builder.setPsduLengthSupport(true); 771 } 772 } catch (IllegalArgumentException e) { 773 Log.w(TAG, "SUPPORTED_PSDU_LENGTH_2_0 not found."); 774 } 775 } else { 776 // This FiRa version is not supported yet. 777 return null; 778 } 779 try { 780 int minRangingInterval = tlvs.getInt(SUPPORTED_MIN_RANGING_INTERVAL_MS); 781 builder.setMinRangingIntervalSupported(minRangingInterval); 782 } catch (IllegalArgumentException e) { 783 Log.w(TAG, "SUPPORTED_MIN_RANGING_INTERVAL_MS not found."); 784 } 785 786 try { 787 int minSlotDurationUs = TlvUtil.rstuToUs(tlvs.getInt(SUPPORTED_MIN_SLOT_DURATION_RSTU)); 788 builder.setMinSlotDurationSupportedUs(minSlotDurationUs); 789 } catch (IllegalArgumentException e) { 790 Log.w(TAG, "SUPPORTED_MIN_SLOT_DURATION not found."); 791 } 792 793 try { 794 int maxRangingSessionNumber = tlvs.getInt(SUPPORTED_MAX_RANGING_SESSION_NUMBER); 795 builder.setMaxRangingSessionNumberSupported(maxRangingSessionNumber); 796 } catch (IllegalArgumentException e) { 797 Log.w(TAG, "SUPPORTED_MAX_RANGING_SESSION_NUMBER not found"); 798 } 799 800 try { 801 byte rssiReporting = tlvs.getByte(SUPPORTED_RSSI_REPORTING); 802 if (isBitSet(rssiReporting, RSSI_REPORTING)) { 803 builder.hasRssiReportingSupport(true); 804 } 805 } catch (IllegalArgumentException e) { 806 Log.w(TAG, "SUPPORTED_RSSI_REPORTING not found."); 807 } 808 809 try { 810 byte diagnostics = tlvs.getByte(SUPPORTED_DIAGNOSTICS); 811 if (isBitSet(diagnostics, DIAGNOSTICS)) { 812 builder.hasDiagnosticsSupport(true); 813 } 814 } catch (IllegalArgumentException e) { 815 Log.w(TAG, "SUPPORTED_DIAGNOSTICS not found."); 816 } 817 818 try { 819 byte[] rangeDataNtfConfigUciBytes = tlvs.getByteArray(SUPPORTED_RANGE_DATA_NTF_CONFIG); 820 int rangeDataNtfConfigUci = 821 new BigInteger(TlvUtil.getReverseBytes(rangeDataNtfConfigUciBytes)).intValue(); 822 EnumSet<FiraParams.RangeDataNtfConfigCapabilityFlag> rangeDataNtfConfigCapabilityFlag = 823 EnumSet.noneOf(FiraParams.RangeDataNtfConfigCapabilityFlag.class); 824 if (isBitSet(rangeDataNtfConfigUci, RANGE_DATA_NTF_CONFIG_ENABLE)) { 825 rangeDataNtfConfigCapabilityFlag.add( 826 FiraParams.RangeDataNtfConfigCapabilityFlag 827 .HAS_RANGE_DATA_NTF_CONFIG_ENABLE); 828 } 829 if (isBitSet(rangeDataNtfConfigUci, RANGE_DATA_NTF_CONFIG_DISABLE)) { 830 rangeDataNtfConfigCapabilityFlag.add( 831 FiraParams.RangeDataNtfConfigCapabilityFlag 832 .HAS_RANGE_DATA_NTF_CONFIG_DISABLE); 833 } 834 if (isBitSet(rangeDataNtfConfigUci, 835 RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_LEVEL_TRIG)) { 836 rangeDataNtfConfigCapabilityFlag.add( 837 FiraParams.RangeDataNtfConfigCapabilityFlag 838 .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_LEVEL_TRIG); 839 } 840 if (isBitSet(rangeDataNtfConfigUci, 841 RANGE_DATA_NTF_CONFIG_ENABLE_AOA_LEVEL_TRIG)) { 842 rangeDataNtfConfigCapabilityFlag.add( 843 FiraParams.RangeDataNtfConfigCapabilityFlag 844 .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_AOA_LEVEL_TRIG); 845 } 846 if (isBitSet(rangeDataNtfConfigUci, 847 RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_LEVEL_TRIG)) { 848 rangeDataNtfConfigCapabilityFlag.add( 849 FiraParams.RangeDataNtfConfigCapabilityFlag 850 .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_LEVEL_TRIG); 851 } 852 if (isBitSet(rangeDataNtfConfigUci, 853 RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_EDGE_TRIG)) { 854 rangeDataNtfConfigCapabilityFlag.add( 855 FiraParams.RangeDataNtfConfigCapabilityFlag 856 .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_EDGE_TRIG); 857 } 858 if (isBitSet(rangeDataNtfConfigUci, 859 RANGE_DATA_NTF_CONFIG_ENABLE_AOA_EDGE_TRIG)) { 860 rangeDataNtfConfigCapabilityFlag.add( 861 FiraParams.RangeDataNtfConfigCapabilityFlag 862 .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_AOA_EDGE_TRIG); 863 } 864 if (isBitSet(rangeDataNtfConfigUci, 865 RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_EDGE_TRIG)) { 866 rangeDataNtfConfigCapabilityFlag.add( 867 FiraParams.RangeDataNtfConfigCapabilityFlag 868 .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_EDGE_TRIG); 869 } 870 builder.setRangeDataNtfConfigCapabilities(rangeDataNtfConfigCapabilityFlag); 871 } catch (IllegalArgumentException e) { 872 Log.w(TAG, "SUPPORTED_RANGE_DATA_NTF_CONFIG not found."); 873 } 874 return builder.build(); 875 } 876 } 877