1 /* 2 * Copyright (C) 2022 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.secure.csml; 18 19 import static com.android.server.uwb.config.CapabilityParam.AOA_AZIMUTH_180; 20 import static com.android.server.uwb.config.CapabilityParam.AOA_AZIMUTH_90; 21 import static com.android.server.uwb.config.CapabilityParam.AOA_ELEVATION; 22 import static com.android.server.uwb.config.CapabilityParam.AOA_FOM; 23 import static com.android.server.uwb.config.CapabilityParam.CC_CONSTRAINT_LENGTH_K3; 24 import static com.android.server.uwb.config.CapabilityParam.CC_CONSTRAINT_LENGTH_K7; 25 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_10; 26 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_12; 27 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_13; 28 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_14; 29 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_5; 30 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_6; 31 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_8; 32 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_9; 33 import static com.android.server.uwb.config.CapabilityParam.DS_TWR_DEFERRED; 34 import static com.android.server.uwb.config.CapabilityParam.DS_TWR_NON_DEFERRED; 35 import static com.android.server.uwb.config.CapabilityParam.DYNAMIC_STS; 36 import static com.android.server.uwb.config.CapabilityParam.DYNAMIC_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY; 37 import static com.android.server.uwb.config.CapabilityParam.INITIATOR; 38 import static com.android.server.uwb.config.CapabilityParam.MANY_TO_MANY; 39 import static com.android.server.uwb.config.CapabilityParam.ONE_TO_MANY; 40 import static com.android.server.uwb.config.CapabilityParam.OWR_UL_TDOA; 41 import static com.android.server.uwb.config.CapabilityParam.RESPONDER; 42 import static com.android.server.uwb.config.CapabilityParam.SP0; 43 import static com.android.server.uwb.config.CapabilityParam.SP1; 44 import static com.android.server.uwb.config.CapabilityParam.SP3; 45 import static com.android.server.uwb.config.CapabilityParam.SS_TWR_DEFERRED; 46 import static com.android.server.uwb.config.CapabilityParam.SS_TWR_NON_DEFERRED; 47 import static com.android.server.uwb.config.CapabilityParam.STATIC_STS; 48 import static com.android.server.uwb.config.CapabilityParam.UNICAST; 49 50 import static com.google.uwb.support.fira.FiraParams.CONSTRAINT_LENGTH_3; 51 import static com.google.uwb.support.fira.FiraParams.CONSTRAINT_LENGTH_7; 52 import static com.google.uwb.support.fira.FiraParams.CONTENTION_BASED_RANGING; 53 import static com.google.uwb.support.fira.FiraParams.MAC_ADDRESS_MODE_2_BYTES; 54 import static com.google.uwb.support.fira.FiraParams.MAC_ADDRESS_MODE_8_BYTES; 55 import static com.google.uwb.support.fira.FiraParams.RANGING_ROUND_USAGE_DL_TDOA; 56 import static com.google.uwb.support.fira.FiraParams.RANGING_ROUND_USAGE_DS_TWR_DEFERRED_MODE; 57 import static com.google.uwb.support.fira.FiraParams.RANGING_ROUND_USAGE_DS_TWR_NON_DEFERRED_MODE; 58 import static com.google.uwb.support.fira.FiraParams.RANGING_ROUND_USAGE_SS_TWR_DEFERRED_MODE; 59 import static com.google.uwb.support.fira.FiraParams.RANGING_ROUND_USAGE_SS_TWR_NON_DEFERRED_MODE; 60 import static com.google.uwb.support.fira.FiraParams.RFRAME_CONFIG_SP0; 61 import static com.google.uwb.support.fira.FiraParams.RFRAME_CONFIG_SP1; 62 import static com.google.uwb.support.fira.FiraParams.RFRAME_CONFIG_SP3; 63 import static com.google.uwb.support.fira.FiraParams.STS_CONFIG_DYNAMIC; 64 import static com.google.uwb.support.fira.FiraParams.STS_CONFIG_DYNAMIC_FOR_CONTROLEE_INDIVIDUAL_KEY; 65 import static com.google.uwb.support.fira.FiraParams.TIME_SCHEDULED_RANGING; 66 67 import androidx.annotation.NonNull; 68 import androidx.annotation.Nullable; 69 70 import com.android.server.uwb.config.CapabilityParam; 71 import com.android.server.uwb.params.TlvBuffer; 72 import com.android.server.uwb.params.TlvDecoderBuffer; 73 74 import com.google.uwb.support.base.FlagEnum; 75 import com.google.uwb.support.fira.FiraParams; 76 import com.google.uwb.support.fira.FiraParams.StsCapabilityFlag; 77 import com.google.uwb.support.fira.FiraProtocolVersion; 78 import com.google.uwb.support.fira.FiraSpecificationParams; 79 80 import java.util.ArrayList; 81 import java.util.EnumSet; 82 import java.util.List; 83 import java.util.Optional; 84 import java.util.stream.Collectors; 85 86 /** 87 * UWB_CAPABILITY defined in 8.5.3.2 88 */ 89 public class UwbCapability { 90 public static final int FIRA_PHY_VERSION_RANGE = 0x80; 91 public static final int FIRA_MAC_VERSION_RANGE = 0x81; 92 public static final int DEVICE_ROLES = 0x82; 93 public static final int RANGING_METHOD = 0x83; 94 public static final int STS_CONFIG = 0x84; 95 public static final int MULTI_NODE_MODE = 0x85; 96 public static final int RANGING_TIME_STRUCT = 0x86; 97 public static final int SCHEDULED_MODE = 0x87; 98 public static final int HOPPING_MODE = 0x88; 99 public static final int BLOCK_STRIDING = 0x89; 100 public static final int UWB_INITIATION_TIME = 0x8A; 101 public static final int CHANNELS = 0x8B; 102 public static final int RFRAME_CONFIG = 0x8C; 103 public static final int CC_CONSTRAINT_LENGTH = 0x8D; 104 public static final int BPRF_PARAMETER_SETS = 0x8E; 105 public static final int HPRF_PARAMETER_SETS = 0x8F; 106 public static final int AOA_SUPPORT = 0x90; 107 public static final int EXTENDED_MAC_ADDRESS = 0x91; 108 public static final int UWB_CAPABILITY_MAX_COUNT = 18; 109 110 public static final int DEFAULT_CHANNEL = 9; 111 112 public final FiraProtocolVersion mMinPhyVersionSupported; 113 public final FiraProtocolVersion mMaxPhyVersionSupported; 114 public final FiraProtocolVersion mMinMacVersionSupported; 115 public final FiraProtocolVersion mMaxMacVersionSupported; 116 public final Optional<EnumSet<FiraParams.DeviceRoleCapabilityFlag>> mDeviceRoles; 117 public final Optional<Byte> mRangingMethod; 118 public final Optional<EnumSet<FiraParams.StsCapabilityFlag>> mStsConfig; 119 public final Optional<EnumSet<FiraParams.MultiNodeCapabilityFlag>> mMultiNodeMode; 120 public final Optional<Byte> mRangingTimeStruct; 121 public final Optional<Byte> mScheduledMode; 122 public final Optional<Boolean> mHoppingMode; 123 public final Optional<Boolean> mBlockStriding; 124 public final Optional<Boolean> mUwbInitiationTime; 125 public final Optional<List<Integer>> mChannels; 126 public final Optional<EnumSet<FiraParams.RframeCapabilityFlag>> mRframeConfig; 127 public final Optional<Byte> mCcConstraintLength; 128 public final Optional<EnumSet<FiraParams.BprfParameterSetCapabilityFlag>> mBprfParameterSet; 129 public final Optional<EnumSet<FiraParams.HprfParameterSetCapabilityFlag>> mHprfParameterSet; 130 public final Optional<EnumSet<FiraParams.AoaCapabilityFlag>> mAoaSupport; 131 public final Optional<Byte> mExtendedMacSupport; 132 UwbCapability(FiraProtocolVersion minPhyVersionSupported, FiraProtocolVersion maxPhyVersionSupported, FiraProtocolVersion minMacVersionSupported, FiraProtocolVersion maxMacVersionSupported, Optional<EnumSet<FiraParams.DeviceRoleCapabilityFlag>> deviceRoles, Optional<Byte> rangingMethod, Optional<EnumSet<FiraParams.StsCapabilityFlag>> stsConfig, Optional<EnumSet<FiraParams.MultiNodeCapabilityFlag>> multiNodeMode, Optional<Byte> rangingTimeStruct, Optional<Byte> scheduledMode, Optional<Boolean> hoppingMode, Optional<Boolean> blockStriding, Optional<Boolean> uwbInitiationTime, Optional<List<Integer>> channels, Optional<EnumSet<FiraParams.RframeCapabilityFlag>> rframeConfig, Optional<Byte> ccConstraintLength, Optional<EnumSet<FiraParams.BprfParameterSetCapabilityFlag>> bprfParameterSet, Optional<EnumSet<FiraParams.HprfParameterSetCapabilityFlag>> hprfParameterSet, Optional<EnumSet<FiraParams.AoaCapabilityFlag>> aoaSupport, Optional<Byte> extendedMacSupport)133 private UwbCapability(FiraProtocolVersion minPhyVersionSupported, 134 FiraProtocolVersion maxPhyVersionSupported, 135 FiraProtocolVersion minMacVersionSupported, 136 FiraProtocolVersion maxMacVersionSupported, 137 Optional<EnumSet<FiraParams.DeviceRoleCapabilityFlag>> deviceRoles, 138 Optional<Byte> rangingMethod, 139 Optional<EnumSet<FiraParams.StsCapabilityFlag>> stsConfig, 140 Optional<EnumSet<FiraParams.MultiNodeCapabilityFlag>> multiNodeMode, 141 Optional<Byte> rangingTimeStruct, 142 Optional<Byte> scheduledMode, 143 Optional<Boolean> hoppingMode, 144 Optional<Boolean> blockStriding, 145 Optional<Boolean> uwbInitiationTime, 146 Optional<List<Integer>> channels, 147 Optional<EnumSet<FiraParams.RframeCapabilityFlag>> rframeConfig, 148 Optional<Byte> ccConstraintLength, 149 Optional<EnumSet<FiraParams.BprfParameterSetCapabilityFlag>> bprfParameterSet, 150 Optional<EnumSet<FiraParams.HprfParameterSetCapabilityFlag>> hprfParameterSet, 151 Optional<EnumSet<FiraParams.AoaCapabilityFlag>> aoaSupport, 152 Optional<Byte> extendedMacSupport) { 153 mMinPhyVersionSupported = minPhyVersionSupported; 154 mMaxPhyVersionSupported = maxPhyVersionSupported; 155 mMinMacVersionSupported = minMacVersionSupported; 156 mMaxMacVersionSupported = maxMacVersionSupported; 157 mDeviceRoles = deviceRoles; 158 mRangingMethod = rangingMethod; 159 mStsConfig = stsConfig; 160 mMultiNodeMode = multiNodeMode; 161 mRangingTimeStruct = rangingTimeStruct; 162 mScheduledMode = scheduledMode; 163 mHoppingMode = hoppingMode; 164 mBlockStriding = blockStriding; 165 mUwbInitiationTime = uwbInitiationTime; 166 mChannels = channels; 167 mRframeConfig = rframeConfig; 168 mCcConstraintLength = ccConstraintLength; 169 mBprfParameterSet = bprfParameterSet; 170 mHprfParameterSet = hprfParameterSet; 171 mAoaSupport = aoaSupport; 172 mExtendedMacSupport = extendedMacSupport; 173 } 174 175 /** 176 * Converts the UwbCapabilities to the bytes which are combined per the TLV of CSML 8.5.3.2. 177 */ 178 @NonNull toBytes()179 public byte[] toBytes() { 180 TlvBuffer.Builder uwbCapabilityBuilder = new TlvBuffer.Builder() 181 .putByteArray(FIRA_PHY_VERSION_RANGE, new byte[]{ 182 (byte) mMinPhyVersionSupported.getMajor(), 183 (byte) mMinPhyVersionSupported.getMinor(), 184 (byte) mMaxPhyVersionSupported.getMajor(), 185 (byte) mMaxPhyVersionSupported.getMinor(), 186 }) 187 .putByteArray(FIRA_MAC_VERSION_RANGE, new byte[]{ 188 (byte) mMinMacVersionSupported.getMajor(), 189 (byte) mMinMacVersionSupported.getMinor(), 190 (byte) mMaxMacVersionSupported.getMajor(), 191 (byte) mMaxMacVersionSupported.getMinor(), 192 }); 193 if (mDeviceRoles.isPresent()) { 194 byte deviceRoles = 0; 195 if (mDeviceRoles.get().contains( 196 FiraParams.DeviceRoleCapabilityFlag.HAS_CONTROLEE_RESPONDER_SUPPORT) 197 && mDeviceRoles.get().contains( 198 FiraParams.DeviceRoleCapabilityFlag.HAS_CONTROLLER_RESPONDER_SUPPORT)) { 199 deviceRoles = (byte) (deviceRoles | RESPONDER); 200 } 201 if (mDeviceRoles.get().contains( 202 FiraParams.DeviceRoleCapabilityFlag.HAS_CONTROLEE_INITIATOR_SUPPORT) 203 && mDeviceRoles.get().contains( 204 FiraParams.DeviceRoleCapabilityFlag.HAS_CONTROLLER_INITIATOR_SUPPORT)) { 205 deviceRoles = (byte) (deviceRoles | INITIATOR); 206 } 207 uwbCapabilityBuilder.putByte(DEVICE_ROLES, deviceRoles); 208 } 209 if (mRangingMethod.isPresent()) { 210 uwbCapabilityBuilder.putByte(RANGING_METHOD, mRangingMethod.get()); 211 } 212 if (mStsConfig.isPresent()) { 213 byte stsConfig = 0; 214 if (mStsConfig.get().contains(FiraParams.StsCapabilityFlag.HAS_STATIC_STS_SUPPORT)) { 215 stsConfig = (byte) (stsConfig | STATIC_STS); 216 } 217 if (mStsConfig.get().contains(FiraParams.StsCapabilityFlag.HAS_DYNAMIC_STS_SUPPORT)) { 218 stsConfig = (byte) (stsConfig | DYNAMIC_STS); 219 } 220 if (mStsConfig.get().contains( 221 FiraParams.StsCapabilityFlag 222 .HAS_DYNAMIC_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT)) { 223 stsConfig = (byte) (stsConfig | DYNAMIC_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY); 224 } 225 uwbCapabilityBuilder.putByte(STS_CONFIG, stsConfig); 226 } 227 if (mMultiNodeMode.isPresent()) { 228 byte multiMode = 0; 229 if (mMultiNodeMode.get().contains( 230 FiraParams.MultiNodeCapabilityFlag.HAS_UNICAST_SUPPORT)) { 231 multiMode = (byte) (multiMode | UNICAST); 232 } 233 if (mMultiNodeMode.get().contains( 234 FiraParams.MultiNodeCapabilityFlag.HAS_ONE_TO_MANY_SUPPORT)) { 235 multiMode = (byte) (multiMode | ONE_TO_MANY); 236 } 237 if (mMultiNodeMode.get().contains( 238 FiraParams.MultiNodeCapabilityFlag.HAS_MANY_TO_MANY_SUPPORT)) { 239 multiMode = (byte) (multiMode | MANY_TO_MANY); 240 } 241 uwbCapabilityBuilder.putByte(MULTI_NODE_MODE, multiMode); 242 } 243 mRangingTimeStruct.ifPresent( 244 aByte -> uwbCapabilityBuilder.putByte(RANGING_TIME_STRUCT, aByte)); 245 246 mScheduledMode.ifPresent( 247 aByte -> uwbCapabilityBuilder.putByte(SCHEDULED_MODE, aByte)); 248 249 mHoppingMode.ifPresent(aBoolean -> uwbCapabilityBuilder.putByte(HOPPING_MODE, 250 (byte) (aBoolean ? 1 : 0))); 251 252 mBlockStriding.ifPresent(aBoolean -> uwbCapabilityBuilder.putByte(BLOCK_STRIDING, 253 (byte) (aBoolean ? 1 : 0))); 254 255 mUwbInitiationTime.ifPresent(aBoolean -> uwbCapabilityBuilder.putByte(UWB_INITIATION_TIME, 256 (byte) (aBoolean ? 1 : 0))); 257 if (mChannels.isPresent()) { 258 byte channels = 0; 259 if (mChannels.get().contains(5)) { 260 channels = (byte) (channels | CHANNEL_5); 261 } 262 if (mChannels.get().contains(6)) { 263 channels = (byte) (channels | CHANNEL_6); 264 } 265 if (mChannels.get().contains(8)) { 266 channels = (byte) (channels | CHANNEL_8); 267 } 268 if (mChannels.get().contains(9)) { 269 channels = (byte) (channels | CHANNEL_9); 270 } 271 if (mChannels.get().contains(10)) { 272 channels = (byte) (channels | CHANNEL_10); 273 } 274 if (mChannels.get().contains(12)) { 275 channels = (byte) (channels | CHANNEL_12); 276 } 277 if (mChannels.get().contains(13)) { 278 channels = (byte) (channels | CHANNEL_13); 279 } 280 if (mChannels.get().contains(14)) { 281 channels = (byte) (channels | CHANNEL_14); 282 } 283 uwbCapabilityBuilder.putByte(CHANNELS, channels); 284 } 285 if (mRframeConfig.isPresent()) { 286 byte rFrameConfig = 0; 287 if (mRframeConfig.get().contains( 288 FiraParams.RframeCapabilityFlag.HAS_SP0_RFRAME_SUPPORT)) { 289 rFrameConfig = (byte) (rFrameConfig | SP0); 290 } 291 if (mRframeConfig.get().contains( 292 FiraParams.RframeCapabilityFlag.HAS_SP1_RFRAME_SUPPORT)) { 293 rFrameConfig = (byte) (rFrameConfig | SP1); 294 } 295 if (mRframeConfig.get().contains( 296 FiraParams.RframeCapabilityFlag.HAS_SP3_RFRAME_SUPPORT)) { 297 rFrameConfig = (byte) (rFrameConfig | SP3); 298 } 299 uwbCapabilityBuilder.putByte(RFRAME_CONFIG, rFrameConfig); 300 } 301 if (mCcConstraintLength.isPresent()) { 302 uwbCapabilityBuilder.putByte(CC_CONSTRAINT_LENGTH, mCcConstraintLength.get()); 303 } 304 if (mBprfParameterSet.isPresent()) { 305 byte bprfParameterSet = (byte) FlagEnum.toInt(mBprfParameterSet.get()); 306 uwbCapabilityBuilder.putByte(BPRF_PARAMETER_SETS, bprfParameterSet); 307 } 308 if (mHprfParameterSet.isPresent()) { 309 byte hprfParameterSet = (byte) FlagEnum.toInt(mHprfParameterSet.get()); 310 uwbCapabilityBuilder.putByte(HPRF_PARAMETER_SETS, hprfParameterSet); 311 } 312 if (mAoaSupport.isPresent()) { 313 byte aoaSupport = 0; 314 if (mAoaSupport.get().contains(FiraParams.AoaCapabilityFlag.HAS_AZIMUTH_SUPPORT)) { 315 aoaSupport = (byte) (aoaSupport | AOA_AZIMUTH_90); 316 } 317 if (mAoaSupport.get().contains(FiraParams.AoaCapabilityFlag.HAS_FULL_AZIMUTH_SUPPORT)) { 318 aoaSupport = (byte) (aoaSupport | AOA_AZIMUTH_180); 319 } 320 if (mAoaSupport.get().contains(FiraParams.AoaCapabilityFlag.HAS_ELEVATION_SUPPORT)) { 321 aoaSupport = (byte) (aoaSupport | AOA_ELEVATION); 322 } 323 if (mAoaSupport.get().contains(FiraParams.AoaCapabilityFlag.HAS_FOM_SUPPORT)) { 324 aoaSupport = (byte) (aoaSupport | AOA_FOM); 325 } 326 uwbCapabilityBuilder.putByte(AOA_SUPPORT, aoaSupport); 327 } 328 mExtendedMacSupport.ifPresent( 329 aByte -> uwbCapabilityBuilder.putByte(EXTENDED_MAC_ADDRESS, aByte.byteValue())); 330 331 return uwbCapabilityBuilder.build().getByteArray(); 332 } 333 isBitSet(int flags, int mask)334 private static boolean isBitSet(int flags, int mask) { 335 return (flags & mask) != 0; 336 } 337 isPresent(TlvDecoderBuffer tlvDecoderBuffer, int tagType)338 private static boolean isPresent(TlvDecoderBuffer tlvDecoderBuffer, int tagType) { 339 try { 340 tlvDecoderBuffer.getByte(tagType); 341 } catch (IllegalArgumentException e) { 342 try { 343 tlvDecoderBuffer.getByteArray(tagType); 344 } catch (IllegalArgumentException e1) { 345 return false; 346 } 347 } 348 return true; 349 } 350 getRangingMethod(@onNull FiraSpecificationParams firaSpecificationParams)351 private static byte getRangingMethod(@NonNull FiraSpecificationParams firaSpecificationParams) { 352 EnumSet<FiraParams.RangingRoundCapabilityFlag> rangingRoundCapabilityFlags = 353 firaSpecificationParams.getRangingRoundCapabilities(); 354 int rangingMethod = 0; 355 if (rangingRoundCapabilityFlags.contains( 356 FiraParams.RangingRoundCapabilityFlag.HAS_DS_TWR_SUPPORT)) { 357 rangingMethod |= DS_TWR_DEFERRED; 358 if (firaSpecificationParams.hasNonDeferredModeSupport()) { 359 rangingMethod |= DS_TWR_NON_DEFERRED; 360 } 361 } 362 if (rangingRoundCapabilityFlags 363 .contains(FiraParams.RangingRoundCapabilityFlag.HAS_SS_TWR_SUPPORT)) { 364 rangingMethod |= SS_TWR_DEFERRED; 365 if (firaSpecificationParams.hasNonDeferredModeSupport()) { 366 rangingMethod |= SS_TWR_NON_DEFERRED; 367 } 368 } 369 return (byte) rangingMethod; 370 } 371 372 /** Converts the FiRaSpecificationParam to UwbCapability. */ 373 @NonNull fromFiRaSpecificationParam( @onNull FiraSpecificationParams firaSpecificationParams)374 public static UwbCapability fromFiRaSpecificationParam( 375 @NonNull FiraSpecificationParams firaSpecificationParams) { 376 return new UwbCapability.Builder() 377 .setMinPhyVersionSupported(firaSpecificationParams.getMinPhyVersionSupported()) 378 .setMaxPhyVersionSupported(firaSpecificationParams.getMaxPhyVersionSupported()) 379 .setMinMacVersionSupported(firaSpecificationParams.getMinMacVersionSupported()) 380 .setMaxMacVersionSupported(firaSpecificationParams.getMaxMacVersionSupported()) 381 .setDeviceRoles(firaSpecificationParams.getDeviceRoleCapabilities()) 382 .setRangingMethod(getRangingMethod(firaSpecificationParams)) 383 .setStsConfig(firaSpecificationParams.getStsCapabilities()) 384 .setMultiNodeMode(firaSpecificationParams.getMultiNodeCapabilities()) 385 .setBlockStriding(firaSpecificationParams.hasBlockStridingSupport()) 386 .setUwbInitiationTime(firaSpecificationParams.hasInitiationTimeSupport()) 387 .setChannels(firaSpecificationParams.getSupportedChannels()) 388 .setRFrameConfig(firaSpecificationParams.getRframeCapabilities()) 389 .setCcConstraintLength(getCcConstraintLength( 390 firaSpecificationParams.getPsduDataRateCapabilities())) 391 .setBprfParameterSet(firaSpecificationParams.getBprfParameterSetCapabilities()) 392 .setHprfParameterSet(firaSpecificationParams.getHprfParameterSetCapabilities()) 393 .setAoaSupport(firaSpecificationParams.getAoaCapabilities()) 394 .build(); 395 } 396 getCcConstraintLength( EnumSet<FiraParams.PsduDataRateCapabilityFlag> psduDataRateCapabilityFlags)397 private static byte getCcConstraintLength( 398 EnumSet<FiraParams.PsduDataRateCapabilityFlag> psduDataRateCapabilityFlags) { 399 byte ccConstraintLength = (byte) 0; 400 if (psduDataRateCapabilityFlags.isEmpty() 401 || psduDataRateCapabilityFlags.contains( 402 FiraParams.PsduDataRateCapabilityFlag.HAS_6M81_SUPPORT) 403 || psduDataRateCapabilityFlags.contains( 404 FiraParams.PsduDataRateCapabilityFlag.HAS_27M2_SUPPORT)) { 405 ccConstraintLength |= (byte) CC_CONSTRAINT_LENGTH_K3; 406 } 407 if (psduDataRateCapabilityFlags.contains( 408 FiraParams.PsduDataRateCapabilityFlag.HAS_7M80_SUPPORT) 409 || psduDataRateCapabilityFlags.contains( 410 FiraParams.PsduDataRateCapabilityFlag.HAS_31M2_SUPPORT)) { 411 ccConstraintLength |= (byte) CC_CONSTRAINT_LENGTH_K7; 412 } 413 414 return ccConstraintLength; 415 } 416 417 /** Checks if the capabilities are compatible. */ isCompatibleTo(@onNull UwbCapability remoteCap)418 boolean isCompatibleTo(@NonNull UwbCapability remoteCap) { 419 // mac version 420 if (mMinMacVersionSupported.getMajor() > remoteCap.mMaxMacVersionSupported.getMajor() 421 || mMaxMacVersionSupported.getMajor() 422 < remoteCap.mMinMacVersionSupported.getMajor()) { 423 return false; 424 } else if (mMinMacVersionSupported.getMinor() > remoteCap.mMaxMacVersionSupported.getMinor() 425 || mMaxMacVersionSupported.getMinor() 426 < remoteCap.mMinMacVersionSupported.getMinor()) { 427 return false; 428 } 429 430 // phy version 431 if (mMinPhyVersionSupported.getMajor() > remoteCap.mMaxPhyVersionSupported.getMajor() 432 || mMaxPhyVersionSupported.getMajor() 433 < remoteCap.mMinPhyVersionSupported.getMajor()) { 434 return false; 435 } else if (mMinPhyVersionSupported.getMinor() > remoteCap.mMaxPhyVersionSupported.getMinor() 436 || mMaxPhyVersionSupported.getMinor() 437 < remoteCap.mMinPhyVersionSupported.getMinor()) { 438 return false; 439 } 440 return true; 441 } 442 443 /** Gets the minimum phy version supported by both devices. */ 444 @NonNull getPreferredPhyVersion(FiraProtocolVersion remoteMinPhyVersion)445 FiraProtocolVersion getPreferredPhyVersion(FiraProtocolVersion remoteMinPhyVersion) { 446 447 if (mMinPhyVersionSupported.getMajor() < remoteMinPhyVersion.getMajor()) { 448 return remoteMinPhyVersion; 449 } else if (mMinPhyVersionSupported.getMajor() > remoteMinPhyVersion.getMajor()) { 450 return mMinPhyVersionSupported; 451 } else if (mMinPhyVersionSupported.getMinor() < remoteMinPhyVersion.getMinor()) { 452 return remoteMinPhyVersion; 453 } 454 return mMinPhyVersionSupported; 455 } 456 457 /** Gets the minimum mac version supported by both devices. */ 458 @NonNull getPreferredMacVersion(FiraProtocolVersion remoteMinMacVersion)459 FiraProtocolVersion getPreferredMacVersion(FiraProtocolVersion remoteMinMacVersion) { 460 461 if (mMinMacVersionSupported.getMajor() < remoteMinMacVersion.getMajor()) { 462 return remoteMinMacVersion; 463 } else if (mMinMacVersionSupported.getMajor() > remoteMinMacVersion.getMajor()) { 464 return mMinMacVersionSupported; 465 } else if (mMinMacVersionSupported.getMinor() < remoteMinMacVersion.getMinor()) { 466 return remoteMinMacVersion; 467 } 468 return mMinMacVersionSupported; 469 } 470 471 @FiraParams.MacAddressMode getPreferredMacAddressMode(Optional<Byte> remoteExtendedMacSupport)472 int getPreferredMacAddressMode(Optional<Byte> remoteExtendedMacSupport) { 473 if (mExtendedMacSupport.isPresent() && mExtendedMacSupport.get() != 0 474 && remoteExtendedMacSupport.isPresent() && remoteExtendedMacSupport.get() != 0) { 475 return MAC_ADDRESS_MODE_8_BYTES; 476 } 477 return MAC_ADDRESS_MODE_2_BYTES; 478 } 479 480 @FiraParams.SchedulingMode getPreferredScheduleMode(Optional<Byte> remoteScheduleMode)481 int getPreferredScheduleMode(Optional<Byte> remoteScheduleMode) { 482 if (mScheduledMode.isPresent() && remoteScheduleMode.isPresent() 483 && (mScheduledMode.get() & remoteScheduleMode.get() 484 & (byte) CapabilityParam.CONTENTION_BASED_RANGING) != 0) { 485 return CONTENTION_BASED_RANGING; 486 } 487 return TIME_SCHEDULED_RANGING; 488 } 489 490 @FiraParams.RframeConfig getPreferredRframeConfig( Optional<EnumSet<FiraParams.RframeCapabilityFlag>> remoteRframeConfig)491 int getPreferredRframeConfig( 492 Optional<EnumSet<FiraParams.RframeCapabilityFlag>> remoteRframeConfig) { 493 if (mRframeConfig.isEmpty() || remoteRframeConfig.isEmpty()) { 494 return RFRAME_CONFIG_SP3; 495 } 496 if (mRframeConfig.get().contains(FiraParams.RframeCapabilityFlag.HAS_SP3_RFRAME_SUPPORT) 497 && remoteRframeConfig.get().contains( 498 FiraParams.RframeCapabilityFlag.HAS_SP3_RFRAME_SUPPORT)) { 499 return RFRAME_CONFIG_SP3; 500 } 501 if (mRframeConfig.get().contains(FiraParams.RframeCapabilityFlag.HAS_SP1_RFRAME_SUPPORT) 502 && remoteRframeConfig.get().contains( 503 FiraParams.RframeCapabilityFlag.HAS_SP1_RFRAME_SUPPORT)) { 504 return RFRAME_CONFIG_SP1; 505 } 506 if (mRframeConfig.get().contains(FiraParams.RframeCapabilityFlag.HAS_SP0_RFRAME_SUPPORT) 507 && remoteRframeConfig.get().contains( 508 FiraParams.RframeCapabilityFlag.HAS_SP0_RFRAME_SUPPORT)) { 509 return RFRAME_CONFIG_SP0; 510 } 511 return RFRAME_CONFIG_SP3; 512 } 513 514 @FiraParams.StsConfig getPreferredStsConfig( Optional<EnumSet<StsCapabilityFlag>> remoteStsCapFlags, boolean isMultiCast)515 int getPreferredStsConfig( 516 Optional<EnumSet<StsCapabilityFlag>> remoteStsCapFlags, 517 boolean isMultiCast) { 518 if (!isMultiCast) { 519 return STS_CONFIG_DYNAMIC; 520 } 521 if (mStsConfig.isEmpty() && remoteStsCapFlags.isEmpty()) { 522 return STS_CONFIG_DYNAMIC_FOR_CONTROLEE_INDIVIDUAL_KEY; 523 } 524 525 if ((remoteStsCapFlags.isEmpty() && mStsConfig.get().contains( 526 StsCapabilityFlag.HAS_DYNAMIC_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT)) 527 || (mStsConfig.isEmpty() && remoteStsCapFlags.get().contains( 528 StsCapabilityFlag.HAS_DYNAMIC_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT)) 529 || (mStsConfig.get().contains( 530 StsCapabilityFlag.HAS_DYNAMIC_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT) 531 && remoteStsCapFlags.get().contains( 532 StsCapabilityFlag 533 .HAS_DYNAMIC_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT))) { 534 return STS_CONFIG_DYNAMIC_FOR_CONTROLEE_INDIVIDUAL_KEY; 535 } 536 537 return STS_CONFIG_DYNAMIC; 538 } 539 540 @NonNull getPreferredChannel(Optional<List<Integer>> remoteChannels)541 Optional<Integer> getPreferredChannel(Optional<List<Integer>> remoteChannels) { 542 if ((mChannels.isEmpty() && remoteChannels.isEmpty()) 543 || (mChannels.isEmpty() && remoteChannels.get().contains(DEFAULT_CHANNEL)) 544 || (remoteChannels.isEmpty() && mChannels.get().contains(DEFAULT_CHANNEL))) { 545 return Optional.of(DEFAULT_CHANNEL); 546 } 547 List<Integer> commonChannels = mChannels.get().stream() 548 .distinct().filter(remoteChannels.get()::contains) 549 .collect(Collectors.toList()); 550 551 return commonChannels.stream().findAny(); 552 } 553 getPreferredHoppingMode(Optional<Boolean> remoteHoppingMode)554 boolean getPreferredHoppingMode(Optional<Boolean> remoteHoppingMode) { 555 if (mHoppingMode.isEmpty() || remoteHoppingMode.isEmpty()) { 556 return false; 557 } 558 return mHoppingMode.get() && remoteHoppingMode.get(); 559 } 560 561 @FiraParams.CcConstraintLength getPreferredConstrainLengthOfConvolutionalCode( Optional<Byte> remoteCcConstrainLength)562 int getPreferredConstrainLengthOfConvolutionalCode( 563 Optional<Byte> remoteCcConstrainLength) { 564 if (mCcConstraintLength.isEmpty() || remoteCcConstrainLength.isEmpty()) { 565 return CONSTRAINT_LENGTH_3; 566 } 567 if ((mCcConstraintLength.get() & remoteCcConstrainLength.get() 568 & CC_CONSTRAINT_LENGTH_K7) != 0) { 569 return CONSTRAINT_LENGTH_7; 570 } 571 return CONSTRAINT_LENGTH_3; 572 } 573 574 @FiraParams.RangingRoundUsage getPreferredRangingMethod(Optional<Byte> remoteRangingMethod)575 int getPreferredRangingMethod(Optional<Byte> remoteRangingMethod) { 576 if (mRangingMethod.isEmpty() || remoteRangingMethod.isEmpty()) { 577 return RANGING_ROUND_USAGE_DS_TWR_DEFERRED_MODE; 578 } 579 580 byte rangingMethodMask = (byte) (mRangingMethod.get() & remoteRangingMethod.get()); 581 582 if ((rangingMethodMask & DS_TWR_DEFERRED) != 0) { 583 return RANGING_ROUND_USAGE_DS_TWR_DEFERRED_MODE; 584 } 585 if ((rangingMethodMask & DS_TWR_NON_DEFERRED) != 0) { 586 return RANGING_ROUND_USAGE_DS_TWR_NON_DEFERRED_MODE; 587 } 588 if ((rangingMethodMask & SS_TWR_DEFERRED) != 0) { 589 return RANGING_ROUND_USAGE_SS_TWR_DEFERRED_MODE; 590 } 591 if ((rangingMethodMask & SS_TWR_NON_DEFERRED) != 0) { 592 return RANGING_ROUND_USAGE_SS_TWR_NON_DEFERRED_MODE; 593 } 594 if (((rangingMethodMask & OWR_UL_TDOA) != 0)) { 595 return RANGING_ROUND_USAGE_DL_TDOA; 596 } 597 return RANGING_ROUND_USAGE_DS_TWR_DEFERRED_MODE; 598 } 599 getPreferredBlockStriding(Optional<Boolean> remoteBlockStriding)600 boolean getPreferredBlockStriding(Optional<Boolean> remoteBlockStriding) { 601 if (mBlockStriding.isEmpty() || remoteBlockStriding.isEmpty()) { 602 return false; 603 } 604 return mBlockStriding.get() && remoteBlockStriding.get(); 605 } 606 607 /** 608 * Converts the UwbCapabilities from the data stream, which is encoded per the CSML 8.5.3.2. 609 * 610 * @return null if the data cannot be decoded per spec. 611 */ 612 @Nullable fromBytes(@onNull byte[] data)613 public static UwbCapability fromBytes(@NonNull byte[] data) { 614 TlvDecoderBuffer uwbCapabilityTlv = new TlvDecoderBuffer(data, UWB_CAPABILITY_MAX_COUNT); 615 uwbCapabilityTlv.parse(); 616 UwbCapability.Builder uwbCapabilityBuilder = new UwbCapability.Builder(); 617 618 if (isPresent(uwbCapabilityTlv, FIRA_PHY_VERSION_RANGE)) { 619 byte[] firaPhyVersionRange = uwbCapabilityTlv.getByteArray(FIRA_PHY_VERSION_RANGE); 620 if (firaPhyVersionRange.length == 4) { 621 FiraProtocolVersion minVersion = new FiraProtocolVersion(firaPhyVersionRange[0], 622 firaPhyVersionRange[1]); 623 FiraProtocolVersion maxVersion = new FiraProtocolVersion(firaPhyVersionRange[2], 624 firaPhyVersionRange[3]); 625 uwbCapabilityBuilder.setMinPhyVersionSupported(minVersion); 626 uwbCapabilityBuilder.setMaxPhyVersionSupported(maxVersion); 627 } 628 } 629 if (isPresent(uwbCapabilityTlv, FIRA_MAC_VERSION_RANGE)) { 630 byte[] firaMacVersionRange = uwbCapabilityTlv.getByteArray(FIRA_MAC_VERSION_RANGE); 631 if (firaMacVersionRange.length == 4) { 632 FiraProtocolVersion minVersion = new FiraProtocolVersion(firaMacVersionRange[0], 633 firaMacVersionRange[1]); 634 FiraProtocolVersion maxVersion = new FiraProtocolVersion(firaMacVersionRange[2], 635 firaMacVersionRange[3]); 636 uwbCapabilityBuilder.setMinMacVersionSupported(minVersion); 637 uwbCapabilityBuilder.setMaxMacVersionSupported(maxVersion); 638 } 639 } 640 if (isPresent(uwbCapabilityTlv, DEVICE_ROLES)) { 641 EnumSet<FiraParams.DeviceRoleCapabilityFlag> deviceRoles = EnumSet.noneOf( 642 FiraParams.DeviceRoleCapabilityFlag.class); 643 byte deviceRolesRaw = uwbCapabilityTlv.getByte(DEVICE_ROLES); 644 if (isBitSet(deviceRolesRaw, INITIATOR)) { 645 deviceRoles.add( 646 FiraParams.DeviceRoleCapabilityFlag.HAS_CONTROLEE_INITIATOR_SUPPORT); 647 deviceRoles.add( 648 FiraParams.DeviceRoleCapabilityFlag.HAS_CONTROLLER_INITIATOR_SUPPORT); 649 } 650 if (isBitSet(deviceRolesRaw, RESPONDER)) { 651 deviceRoles.add( 652 FiraParams.DeviceRoleCapabilityFlag.HAS_CONTROLEE_RESPONDER_SUPPORT); 653 deviceRoles.add( 654 FiraParams.DeviceRoleCapabilityFlag.HAS_CONTROLLER_RESPONDER_SUPPORT); 655 } 656 uwbCapabilityBuilder.setDeviceRoles(deviceRoles); 657 } 658 if (isPresent(uwbCapabilityTlv, RANGING_METHOD)) { 659 uwbCapabilityBuilder.setRangingMethod(uwbCapabilityTlv.getByte(RANGING_METHOD)); 660 } 661 if (isPresent(uwbCapabilityTlv, STS_CONFIG)) { 662 EnumSet<FiraParams.StsCapabilityFlag> stsConfig = EnumSet.noneOf( 663 FiraParams.StsCapabilityFlag.class); 664 byte stsConfigRaw = uwbCapabilityTlv.getByte(STS_CONFIG); 665 if (isBitSet(stsConfigRaw, STATIC_STS)) { 666 stsConfig.add(FiraParams.StsCapabilityFlag.HAS_STATIC_STS_SUPPORT); 667 } 668 if (isBitSet(stsConfigRaw, DYNAMIC_STS)) { 669 stsConfig.add(FiraParams.StsCapabilityFlag.HAS_DYNAMIC_STS_SUPPORT); 670 } 671 if (isBitSet(stsConfigRaw, DYNAMIC_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY)) { 672 stsConfig.add( 673 FiraParams.StsCapabilityFlag 674 .HAS_DYNAMIC_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT); 675 } 676 uwbCapabilityBuilder.setStsConfig(stsConfig); 677 } 678 if (isPresent(uwbCapabilityTlv, MULTI_NODE_MODE)) { 679 EnumSet<FiraParams.MultiNodeCapabilityFlag> multiNodeMode = EnumSet.noneOf( 680 FiraParams.MultiNodeCapabilityFlag.class); 681 byte multiNodeRaw = uwbCapabilityTlv.getByte(MULTI_NODE_MODE); 682 if (isBitSet(multiNodeRaw, UNICAST)) { 683 multiNodeMode.add(FiraParams.MultiNodeCapabilityFlag.HAS_UNICAST_SUPPORT); 684 } 685 if (isBitSet(multiNodeRaw, ONE_TO_MANY)) { 686 multiNodeMode.add(FiraParams.MultiNodeCapabilityFlag.HAS_ONE_TO_MANY_SUPPORT); 687 } 688 if (isBitSet(multiNodeRaw, MANY_TO_MANY)) { 689 multiNodeMode.add(FiraParams.MultiNodeCapabilityFlag.HAS_MANY_TO_MANY_SUPPORT); 690 } 691 uwbCapabilityBuilder.setMultiMode(multiNodeMode); 692 } 693 if (isPresent(uwbCapabilityTlv, RANGING_TIME_STRUCT)) { 694 uwbCapabilityBuilder.setRangingTimeStruct( 695 uwbCapabilityTlv.getByte(RANGING_TIME_STRUCT)); 696 } 697 if (isPresent(uwbCapabilityTlv, SCHEDULED_MODE)) { 698 uwbCapabilityBuilder.setScheduledMode(uwbCapabilityTlv.getByte(SCHEDULED_MODE)); 699 } 700 if (isPresent(uwbCapabilityTlv, HOPPING_MODE)) { 701 uwbCapabilityBuilder.setHoppingMode(uwbCapabilityTlv.getByte(HOPPING_MODE) == 1); 702 } 703 if (isPresent(uwbCapabilityTlv, BLOCK_STRIDING)) { 704 uwbCapabilityBuilder.setBlockStriding(uwbCapabilityTlv.getByte(BLOCK_STRIDING) == 1); 705 } 706 if (isPresent(uwbCapabilityTlv, UWB_INITIATION_TIME)) { 707 uwbCapabilityBuilder.setUwbInitiationTime( 708 uwbCapabilityTlv.getByte(UWB_INITIATION_TIME) == 1); 709 } 710 if (isPresent(uwbCapabilityTlv, CHANNELS)) { 711 List<Integer> channels = new ArrayList<>(); 712 byte channelsRaw = uwbCapabilityTlv.getByte(CHANNELS); 713 if (isBitSet(channelsRaw, CHANNEL_5)) { 714 channels.add(5); 715 } 716 if (isBitSet(channelsRaw, CHANNEL_6)) { 717 channels.add(6); 718 } 719 if (isBitSet(channelsRaw, CHANNEL_8)) { 720 channels.add(8); 721 } 722 if (isBitSet(channelsRaw, CHANNEL_9)) { 723 channels.add(9); 724 } 725 if (isBitSet(channelsRaw, CHANNEL_10)) { 726 channels.add(10); 727 } 728 if (isBitSet(channelsRaw, CHANNEL_12)) { 729 channels.add(12); 730 } 731 if (isBitSet(channelsRaw, CHANNEL_13)) { 732 channels.add(13); 733 } 734 if (isBitSet(channelsRaw, CHANNEL_14)) { 735 channels.add(14); 736 } 737 uwbCapabilityBuilder.setChannels(channels); 738 } 739 if (isPresent(uwbCapabilityTlv, RFRAME_CONFIG)) { 740 EnumSet<FiraParams.RframeCapabilityFlag> rFrameConfig = EnumSet.noneOf( 741 FiraParams.RframeCapabilityFlag.class); 742 byte rFrameConfigRaw = uwbCapabilityTlv.getByte(RFRAME_CONFIG); 743 if (isBitSet(rFrameConfigRaw, SP0)) { 744 rFrameConfig.add(FiraParams.RframeCapabilityFlag.HAS_SP0_RFRAME_SUPPORT); 745 } 746 if (isBitSet(rFrameConfigRaw, SP1)) { 747 rFrameConfig.add(FiraParams.RframeCapabilityFlag.HAS_SP1_RFRAME_SUPPORT); 748 } 749 if (isBitSet(rFrameConfigRaw, SP3)) { 750 rFrameConfig.add(FiraParams.RframeCapabilityFlag.HAS_SP3_RFRAME_SUPPORT); 751 } 752 uwbCapabilityBuilder.setRFrameConfig(rFrameConfig); 753 } 754 if (isPresent(uwbCapabilityTlv, CC_CONSTRAINT_LENGTH)) { 755 byte ccConstraintLength = uwbCapabilityTlv.getByte(CC_CONSTRAINT_LENGTH); 756 uwbCapabilityBuilder.setCcConstraintLength(ccConstraintLength); 757 } 758 if (isPresent(uwbCapabilityTlv, AOA_SUPPORT)) { 759 EnumSet<FiraParams.AoaCapabilityFlag> aoaSupport = EnumSet.noneOf( 760 FiraParams.AoaCapabilityFlag.class); 761 byte aoaSupportRaw = uwbCapabilityTlv.getByte(AOA_SUPPORT); 762 if (isBitSet(aoaSupportRaw, AOA_AZIMUTH_90)) { 763 aoaSupport.add(FiraParams.AoaCapabilityFlag.HAS_AZIMUTH_SUPPORT); 764 } 765 if (isBitSet(aoaSupportRaw, AOA_AZIMUTH_180)) { 766 aoaSupport.add(FiraParams.AoaCapabilityFlag.HAS_FULL_AZIMUTH_SUPPORT); 767 } 768 if (isBitSet(aoaSupportRaw, AOA_ELEVATION)) { 769 aoaSupport.add(FiraParams.AoaCapabilityFlag.HAS_ELEVATION_SUPPORT); 770 } 771 if (isBitSet(aoaSupportRaw, AOA_FOM)) { 772 aoaSupport.add(FiraParams.AoaCapabilityFlag.HAS_FOM_SUPPORT); 773 } 774 uwbCapabilityBuilder.setAoaSupport(aoaSupport); 775 } 776 if (isPresent(uwbCapabilityTlv, BPRF_PARAMETER_SETS)) { 777 byte bprfSets = uwbCapabilityTlv.getByte(BPRF_PARAMETER_SETS); 778 int bprfSetsValue = Integer.valueOf(bprfSets); 779 EnumSet<FiraParams.BprfParameterSetCapabilityFlag> bprfFlag; 780 bprfFlag = FlagEnum.toEnumSet(bprfSetsValue, 781 FiraParams.BprfParameterSetCapabilityFlag.values()); 782 uwbCapabilityBuilder.setBprfParameterSet(bprfFlag); 783 } 784 if (isPresent(uwbCapabilityTlv, HPRF_PARAMETER_SETS)) { 785 byte hprfSets = uwbCapabilityTlv.getByte(HPRF_PARAMETER_SETS); 786 int hprfSetsValue = Integer.valueOf(hprfSets); 787 EnumSet<FiraParams.HprfParameterSetCapabilityFlag> hprfFlag; 788 hprfFlag = FlagEnum.toEnumSet(hprfSetsValue, 789 FiraParams.HprfParameterSetCapabilityFlag.values()); 790 uwbCapabilityBuilder.setHprfParameterSet(hprfFlag); 791 } 792 if (isPresent(uwbCapabilityTlv, EXTENDED_MAC_ADDRESS)) { 793 uwbCapabilityBuilder.setExtendedMacSupport( 794 uwbCapabilityTlv.getByte(EXTENDED_MAC_ADDRESS)); 795 } 796 return uwbCapabilityBuilder.build(); 797 } 798 799 /** Builder for UwbCapabilities */ 800 public static class Builder { 801 // Set all default protocol version to FiRa 1.1 802 private FiraProtocolVersion mMinPhyVersionSupported = new FiraProtocolVersion(1, 1); 803 private FiraProtocolVersion mMaxPhyVersionSupported = new FiraProtocolVersion(1, 1); 804 private FiraProtocolVersion mMinMacVersionSupported = new FiraProtocolVersion(1, 1); 805 private FiraProtocolVersion mMaxMacVersionSupported = new FiraProtocolVersion(1, 1); 806 private Optional<EnumSet<FiraParams.DeviceRoleCapabilityFlag>> mDeviceRoles = 807 Optional.empty(); 808 private Optional<Byte> mRangingMethod = Optional.empty(); 809 private Optional<EnumSet<FiraParams.StsCapabilityFlag>> mStsConfig = Optional.empty(); 810 private Optional<EnumSet<FiraParams.MultiNodeCapabilityFlag>> mMultiNodeMode = 811 Optional.empty(); 812 private Optional<Byte> mRangingTimeStruct = Optional.empty(); 813 private Optional<Byte> mScheduledMode = Optional.empty(); 814 private Optional<Boolean> mHoppingMode = Optional.empty(); 815 private Optional<Boolean> mBlockStriding = Optional.empty(); 816 private Optional<Boolean> mUwbInitiationTime = Optional.empty(); 817 private Optional<List<Integer>> mChannels = Optional.empty(); 818 private Optional<EnumSet<FiraParams.RframeCapabilityFlag>> mRframeConfig = Optional.empty(); 819 private Optional<Byte> mCcConstraintLength = 820 Optional.empty(); 821 private Optional<EnumSet<FiraParams.BprfParameterSetCapabilityFlag>> mBprfParameterSet = 822 Optional.empty(); 823 private Optional<EnumSet<FiraParams.HprfParameterSetCapabilityFlag>> mHprfParameterSet = 824 Optional.empty(); 825 private Optional<EnumSet<FiraParams.AoaCapabilityFlag>> mAoaSupport = Optional.empty(); 826 private Optional<Byte> mExtendedMacSupport = Optional.empty(); 827 setMinPhyVersionSupported( FiraProtocolVersion minPhyVersionSupported)828 UwbCapability.Builder setMinPhyVersionSupported( 829 FiraProtocolVersion minPhyVersionSupported) { 830 mMinPhyVersionSupported = minPhyVersionSupported; 831 return this; 832 } 833 setMaxPhyVersionSupported( FiraProtocolVersion maxPhyVersionSupported)834 UwbCapability.Builder setMaxPhyVersionSupported( 835 FiraProtocolVersion maxPhyVersionSupported) { 836 mMaxPhyVersionSupported = maxPhyVersionSupported; 837 return this; 838 } 839 setMinMacVersionSupported( FiraProtocolVersion minMacVersionSupported)840 UwbCapability.Builder setMinMacVersionSupported( 841 FiraProtocolVersion minMacVersionSupported) { 842 mMinMacVersionSupported = minMacVersionSupported; 843 return this; 844 } 845 setMaxMacVersionSupported( FiraProtocolVersion maxMacVersionSupported)846 UwbCapability.Builder setMaxMacVersionSupported( 847 FiraProtocolVersion maxMacVersionSupported) { 848 mMaxMacVersionSupported = maxMacVersionSupported; 849 return this; 850 } 851 setDeviceRoles( EnumSet<FiraParams.DeviceRoleCapabilityFlag> deviceRoles)852 UwbCapability.Builder setDeviceRoles( 853 EnumSet<FiraParams.DeviceRoleCapabilityFlag> deviceRoles) { 854 mDeviceRoles = Optional.of(deviceRoles); 855 return this; 856 } 857 setRangingMethod( byte rangingMethod)858 UwbCapability.Builder setRangingMethod( 859 byte rangingMethod) { 860 mRangingMethod = Optional.of(rangingMethod); 861 return this; 862 } 863 setStsConfig( EnumSet<FiraParams.StsCapabilityFlag> stsConfig)864 UwbCapability.Builder setStsConfig( 865 EnumSet<FiraParams.StsCapabilityFlag> stsConfig) { 866 mStsConfig = Optional.of(stsConfig); 867 return this; 868 } 869 setMultiMode( EnumSet<FiraParams.MultiNodeCapabilityFlag> multiNodeMode)870 UwbCapability.Builder setMultiMode( 871 EnumSet<FiraParams.MultiNodeCapabilityFlag> multiNodeMode) { 872 mMultiNodeMode = Optional.of(multiNodeMode); 873 return this; 874 } 875 setRangingTimeStruct(Byte rangingTimeStruct)876 UwbCapability.Builder setRangingTimeStruct(Byte rangingTimeStruct) { 877 mRangingTimeStruct = Optional.of(rangingTimeStruct); 878 return this; 879 } 880 setScheduledMode(Byte scheduledMode)881 UwbCapability.Builder setScheduledMode(Byte scheduledMode) { 882 mScheduledMode = Optional.of(scheduledMode); 883 return this; 884 } 885 setHoppingMode(Boolean hoppingMode)886 UwbCapability.Builder setHoppingMode(Boolean hoppingMode) { 887 mHoppingMode = Optional.of(hoppingMode); 888 return this; 889 } 890 setBlockStriding(Boolean blockStriding)891 UwbCapability.Builder setBlockStriding(Boolean blockStriding) { 892 mBlockStriding = Optional.of(blockStriding); 893 return this; 894 } 895 setUwbInitiationTime(Boolean uwbInitiationTime)896 UwbCapability.Builder setUwbInitiationTime(Boolean uwbInitiationTime) { 897 mUwbInitiationTime = Optional.of(uwbInitiationTime); 898 return this; 899 } 900 setChannels(List<Integer> channels)901 UwbCapability.Builder setChannels(List<Integer> channels) { 902 mChannels = Optional.of(channels); 903 return this; 904 } 905 setMultiNodeMode( EnumSet<FiraParams.MultiNodeCapabilityFlag> multiNodeMode)906 UwbCapability.Builder setMultiNodeMode( 907 EnumSet<FiraParams.MultiNodeCapabilityFlag> multiNodeMode) { 908 mMultiNodeMode = Optional.of(multiNodeMode); 909 return this; 910 } 911 setRFrameConfig( EnumSet<FiraParams.RframeCapabilityFlag> rFrameConfig)912 UwbCapability.Builder setRFrameConfig( 913 EnumSet<FiraParams.RframeCapabilityFlag> rFrameConfig) { 914 mRframeConfig = Optional.of(rFrameConfig); 915 return this; 916 } 917 setCcConstraintLength(byte ccConstraintLength)918 UwbCapability.Builder setCcConstraintLength(byte ccConstraintLength) { 919 mCcConstraintLength = Optional.of(ccConstraintLength); 920 return this; 921 } 922 setBprfParameterSet( EnumSet<FiraParams.BprfParameterSetCapabilityFlag> bprfParameterSet)923 UwbCapability.Builder setBprfParameterSet( 924 EnumSet<FiraParams.BprfParameterSetCapabilityFlag> bprfParameterSet) { 925 mBprfParameterSet = Optional.of(bprfParameterSet); 926 return this; 927 } 928 setHprfParameterSet( EnumSet<FiraParams.HprfParameterSetCapabilityFlag> hprfParameterSet)929 UwbCapability.Builder setHprfParameterSet( 930 EnumSet<FiraParams.HprfParameterSetCapabilityFlag> hprfParameterSet) { 931 mHprfParameterSet = Optional.of(hprfParameterSet); 932 return this; 933 } 934 setAoaSupport( EnumSet<FiraParams.AoaCapabilityFlag> aoaSupport)935 UwbCapability.Builder setAoaSupport( 936 EnumSet<FiraParams.AoaCapabilityFlag> aoaSupport) { 937 mAoaSupport = Optional.of(aoaSupport); 938 return this; 939 } 940 setExtendedMacSupport(Byte extendedMacSupport)941 UwbCapability.Builder setExtendedMacSupport(Byte extendedMacSupport) { 942 mExtendedMacSupport = Optional.of(extendedMacSupport); 943 return this; 944 } 945 build()946 UwbCapability build() { 947 return new UwbCapability( 948 mMinPhyVersionSupported, 949 mMaxPhyVersionSupported, 950 mMinMacVersionSupported, 951 mMaxMacVersionSupported, 952 mDeviceRoles, 953 mRangingMethod, 954 mStsConfig, 955 mMultiNodeMode, 956 mRangingTimeStruct, 957 mScheduledMode, 958 mHoppingMode, 959 mBlockStriding, 960 mUwbInitiationTime, 961 mChannels, 962 mRframeConfig, 963 mCcConstraintLength, 964 mBprfParameterSet, 965 mHprfParameterSet, 966 mAoaSupport, 967 mExtendedMacSupport 968 ); 969 } 970 } 971 } 972