/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.uwb.params; import static com.android.server.uwb.config.CapabilityParam.ADS_TWR; import static com.android.server.uwb.config.CapabilityParam.ADVERTISER; import static com.android.server.uwb.config.CapabilityParam.AOA_AZIMUTH_180; import static com.android.server.uwb.config.CapabilityParam.AOA_AZIMUTH_90; import static com.android.server.uwb.config.CapabilityParam.AOA_ELEVATION; import static com.android.server.uwb.config.CapabilityParam.AOA_FOM; import static com.android.server.uwb.config.CapabilityParam.AOA_RESULT_REQ_INTERLEAVING; import static com.android.server.uwb.config.CapabilityParam.BLOCK_BASED_SCHEDULING; import static com.android.server.uwb.config.CapabilityParam.BLOCK_STRIDING; import static com.android.server.uwb.config.CapabilityParam.CC_CONSTRAINT_LENGTH_K3; import static com.android.server.uwb.config.CapabilityParam.CC_CONSTRAINT_LENGTH_K7; import static com.android.server.uwb.config.CapabilityParam.CHANNEL_10; import static com.android.server.uwb.config.CapabilityParam.CHANNEL_12; import static com.android.server.uwb.config.CapabilityParam.CHANNEL_13; import static com.android.server.uwb.config.CapabilityParam.CHANNEL_14; import static com.android.server.uwb.config.CapabilityParam.CHANNEL_5; import static com.android.server.uwb.config.CapabilityParam.CHANNEL_6; import static com.android.server.uwb.config.CapabilityParam.CHANNEL_8; import static com.android.server.uwb.config.CapabilityParam.CHANNEL_9; import static com.android.server.uwb.config.CapabilityParam.CONSTRAINT_LENGTH_3; import static com.android.server.uwb.config.CapabilityParam.CONSTRAINT_LENGTH_7; import static com.android.server.uwb.config.CapabilityParam.CONTENTION_BASED_RANGING; import static com.android.server.uwb.config.CapabilityParam.DIAGNOSTICS; import static com.android.server.uwb.config.CapabilityParam.DS_TWR_DEFERRED; import static com.android.server.uwb.config.CapabilityParam.DS_TWR_NON_DEFERRED; import static com.android.server.uwb.config.CapabilityParam.DT_ANCHOR; import static com.android.server.uwb.config.CapabilityParam.DT_TAG; import static com.android.server.uwb.config.CapabilityParam.DT_TAG_BLOCK_SKIPPING; import static com.android.server.uwb.config.CapabilityParam.DYNAMIC_STS; import static com.android.server.uwb.config.CapabilityParam.DYNAMIC_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY; import static com.android.server.uwb.config.CapabilityParam.ESS_TWR_NON_DEFERRED; import static com.android.server.uwb.config.CapabilityParam.EXTENDED_MAC_ADDRESS; import static com.android.server.uwb.config.CapabilityParam.HOPPING_MODE; import static com.android.server.uwb.config.CapabilityParam.INITIATOR; import static com.android.server.uwb.config.CapabilityParam.INTERVAL_BASED_SCHEDULING; import static com.android.server.uwb.config.CapabilityParam.MANY_TO_MANY; import static com.android.server.uwb.config.CapabilityParam.OBSERVER; import static com.android.server.uwb.config.CapabilityParam.ONE_TO_MANY; import static com.android.server.uwb.config.CapabilityParam.OWR_AOA; import static com.android.server.uwb.config.CapabilityParam.OWR_DL_TDOA; import static com.android.server.uwb.config.CapabilityParam.OWR_UL_TDOA; import static com.android.server.uwb.config.CapabilityParam.PROVISIONED_STS; import static com.android.server.uwb.config.CapabilityParam.PROVISIONED_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY; import static com.android.server.uwb.config.CapabilityParam.PSDU_LENGTH_SUPPORT; import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_DISABLE; import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE; import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_AOA_EDGE_TRIG; import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_AOA_LEVEL_TRIG; import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_EDGE_TRIG; import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_LEVEL_TRIG; import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_EDGE_TRIG; import static com.android.server.uwb.config.CapabilityParam.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_LEVEL_TRIG; import static com.android.server.uwb.config.CapabilityParam.RESPONDER; import static com.android.server.uwb.config.CapabilityParam.RSSI_REPORTING; import static com.android.server.uwb.config.CapabilityParam.SP0; import static com.android.server.uwb.config.CapabilityParam.SP1; import static com.android.server.uwb.config.CapabilityParam.SP3; import static com.android.server.uwb.config.CapabilityParam.SS_TWR_DEFERRED; import static com.android.server.uwb.config.CapabilityParam.SS_TWR_NON_DEFERRED; import static com.android.server.uwb.config.CapabilityParam.STATIC_STS; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_AOA_RESULT_REQ_INTERLEAVING; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_AOA_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_AOA_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_BLOCK_STRIDING_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_BLOCK_STRIDING_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_BPRF_PARAMETER_SETS_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_BPRF_PARAMETER_SETS_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_CC_CONSTRAINT_LENGTH_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_CC_CONSTRAINT_LENGTH_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_CHANNELS_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_CHANNELS_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DEVICE_ROLES_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DEVICE_ROLES_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DEVICE_TYPE_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DIAGNOSTICS; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DT_TAG_BLOCK_SKIPPING_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DT_TAG_MAX_ACTIVE_RR_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_EXTENDED_MAC_ADDRESS_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_EXTENDED_MAC_ADDRESS_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_FIRA_MAC_VERSION_RANGE_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_FIRA_MAC_VERSION_RANGE_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_FIRA_PHY_VERSION_RANGE_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_FIRA_PHY_VERSION_RANGE_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_HOPPING_MODE_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_HOPPING_MODE_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_HPRF_PARAMETER_SETS_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_HPRF_PARAMETER_SETS_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MAX_MESSAGE_SIZE_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MAX_MESSAGE_SIZE_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MAX_RANGING_SESSION_NUMBER; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MIN_RANGING_INTERVAL_MS; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MIN_SLOT_DURATION_RSTU; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MULTI_NODE_MODES_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MULTI_NODE_MODES_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_PSDU_LENGTH_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGE_DATA_NTF_CONFIG; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGING_METHOD_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGING_METHOD_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGING_TIME_STRUCT_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGING_TIME_STRUCT_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RFRAME_CONFIG_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RFRAME_CONFIG_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RSSI_REPORTING; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_SCHEDULED_MODE_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_SCHEDULED_MODE_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_SESSION_KEY_LENGTH_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_STS_CONFIG_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_STS_CONFIG_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_SUSPEND_RANGING_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_UWB_INITIATION_TIME_VER_1_0; import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_UWB_INITIATION_TIME_VER_2_0; import static com.android.server.uwb.config.CapabilityParam.TIME_SCHEDULED_RANGING; import static com.android.server.uwb.config.CapabilityParam.UNICAST; import static com.android.server.uwb.config.CapabilityParam.UT_ANCHOR; import static com.android.server.uwb.config.CapabilityParam.UT_SYNCHRONIZATION_ANCHOR; import static com.android.server.uwb.config.CapabilityParam.UT_TAG; import static com.android.server.uwb.config.CapabilityParam.UWB_INITIATION_TIME; import android.util.Log; import com.android.server.uwb.UwbInjector; import com.google.uwb.support.base.FlagEnum; import com.google.uwb.support.base.Params; import com.google.uwb.support.base.ProtocolVersion; import com.google.uwb.support.fira.FiraParams; import com.google.uwb.support.fira.FiraParams.BprfParameterSetCapabilityFlag; import com.google.uwb.support.fira.FiraParams.CcConstraintLengthCapabilitiesFlag; import com.google.uwb.support.fira.FiraParams.DeviceRoleCapabilityFlag; import com.google.uwb.support.fira.FiraParams.HprfParameterSetCapabilityFlag; import com.google.uwb.support.fira.FiraParams.MultiNodeCapabilityFlag; import com.google.uwb.support.fira.FiraParams.PsduDataRateCapabilityFlag; import com.google.uwb.support.fira.FiraParams.RangingRoundCapabilityFlag; import com.google.uwb.support.fira.FiraParams.RangingTimeStructCapabilitiesFlag; import com.google.uwb.support.fira.FiraParams.RframeCapabilityFlag; import com.google.uwb.support.fira.FiraParams.SchedulingModeCapabilitiesFlag; import com.google.uwb.support.fira.FiraParams.StsCapabilityFlag; import com.google.uwb.support.fira.FiraProtocolVersion; import com.google.uwb.support.fira.FiraSpecificationParams; import java.math.BigInteger; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import java.util.stream.IntStream; public class FiraDecoder extends TlvDecoder { private static final String TAG = "FiraDecoder"; private final UwbInjector mUwbInjector; public FiraDecoder(UwbInjector uwbInjector) { mUwbInjector = uwbInjector; } @Override public T getParams(TlvDecoderBuffer tlvs, Class paramType, ProtocolVersion protocolVersion) { if (FiraSpecificationParams.class.equals(paramType)) { // The "protocolVersion" is always expected to be of type "FiraProtocolVersion" here, // but in case it's not, we use a backup value of "PROTOCOL_VERSION_1_1". FiraProtocolVersion uwbsFiraProtocolVersion = (protocolVersion instanceof FiraProtocolVersion) ? (FiraProtocolVersion) protocolVersion : FiraParams.PROTOCOL_VERSION_1_1; return (T) getFiraSpecificationParamsFromTlvBuffer(tlvs, uwbsFiraProtocolVersion); } return null; } private static boolean isBitSet(int flags, int mask) { return (flags & mask) != 0; } private FiraSpecificationParams getFiraSpecificationParamsFromTlvBuffer(TlvDecoderBuffer tlvs, ProtocolVersion protocolVersion) { FiraSpecificationParams.Builder builder = new FiraSpecificationParams.Builder(); byte[] versionCheck = tlvs.getByteArray(SUPPORTED_FIRA_PHY_VERSION_RANGE_VER_2_0); if (versionCheck.length == 1) { // FiRa Version 1.0 byte[] phyVersions = tlvs.getByteArray(SUPPORTED_FIRA_PHY_VERSION_RANGE_VER_1_0); builder.setMinPhyVersionSupported(FiraProtocolVersion.fromBytes(phyVersions, 0)); builder.setMaxPhyVersionSupported(FiraProtocolVersion.fromBytes(phyVersions, 2)); byte[] macVersions = tlvs.getByteArray(SUPPORTED_FIRA_MAC_VERSION_RANGE_VER_1_0); builder.setMinMacVersionSupported(FiraProtocolVersion.fromBytes(macVersions, 0)); builder.setMaxMacVersionSupported(FiraProtocolVersion.fromBytes(macVersions, 2)); byte deviceRolesUci = tlvs.getByte(SUPPORTED_DEVICE_ROLES_VER_1_0); EnumSet deviceRoles = EnumSet.noneOf(DeviceRoleCapabilityFlag.class); if (isBitSet(deviceRolesUci, INITIATOR)) { // This assumes both controller + controlee is supported. deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLLER_INITIATOR_SUPPORT); deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLEE_INITIATOR_SUPPORT); } if (isBitSet(deviceRolesUci, RESPONDER)) { // This assumes both controller + controlee is supported. deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLLER_RESPONDER_SUPPORT); deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLEE_RESPONDER_SUPPORT); } builder.setDeviceRoleCapabilities(deviceRoles); byte rangingMethodUci = tlvs.getByte(SUPPORTED_RANGING_METHOD_VER_1_0); EnumSet rangingRoundFlag = EnumSet.noneOf( RangingRoundCapabilityFlag.class); if (isBitSet(rangingMethodUci, DS_TWR_DEFERRED)) { rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_DS_TWR_SUPPORT); } if (isBitSet(rangingMethodUci, SS_TWR_DEFERRED)) { rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_SS_TWR_SUPPORT); } builder.setRangingRoundCapabilities(rangingRoundFlag); // TODO(b/209053358): This does not align with UCI spec. if (isBitSet(rangingMethodUci, DS_TWR_NON_DEFERRED) || isBitSet(rangingMethodUci, SS_TWR_NON_DEFERRED)) { builder.hasNonDeferredModeSupport(true); } byte stsConfigUci = tlvs.getByte(SUPPORTED_STS_CONFIG_VER_1_0); EnumSet stsCapabilityFlag = EnumSet.noneOf(StsCapabilityFlag.class); if (isBitSet(stsConfigUci, STATIC_STS)) { stsCapabilityFlag.add(StsCapabilityFlag.HAS_STATIC_STS_SUPPORT); } if (isBitSet(stsConfigUci, DYNAMIC_STS)) { stsCapabilityFlag.add(StsCapabilityFlag.HAS_DYNAMIC_STS_SUPPORT); } if (isBitSet(stsConfigUci, DYNAMIC_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY)) { stsCapabilityFlag.add( StsCapabilityFlag.HAS_DYNAMIC_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT); } if (isBitSet(stsConfigUci, PROVISIONED_STS)) { stsCapabilityFlag.add(StsCapabilityFlag.HAS_PROVISIONED_STS_SUPPORT); } if (isBitSet(stsConfigUci, PROVISIONED_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY)) { stsCapabilityFlag.add( StsCapabilityFlag.HAS_PROVISIONED_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT); } builder.setStsCapabilities(stsCapabilityFlag); byte multiNodeUci = tlvs.getByte(SUPPORTED_MULTI_NODE_MODES_VER_1_0); EnumSet multiNodeFlag = EnumSet.noneOf(MultiNodeCapabilityFlag.class); if (isBitSet(multiNodeUci, UNICAST)) { multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_UNICAST_SUPPORT); } if (isBitSet(multiNodeUci, ONE_TO_MANY)) { multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_ONE_TO_MANY_SUPPORT); } if (isBitSet(multiNodeUci, MANY_TO_MANY)) { multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_MANY_TO_MANY_SUPPORT); } builder.setMultiNodeCapabilities(multiNodeFlag); byte rangingTimeStructUci = tlvs.getByte(SUPPORTED_RANGING_TIME_STRUCT_VER_1_0); EnumSet rangingTimeStructFlag = EnumSet.noneOf(RangingTimeStructCapabilitiesFlag.class); if (protocolVersion.getMajor() <= 2 && isBitSet(rangingTimeStructUci, INTERVAL_BASED_SCHEDULING)) { rangingTimeStructFlag.add( RangingTimeStructCapabilitiesFlag.HAS_INTERVAL_BASED_SCHEDULING_SUPPORT); } if (isBitSet(rangingTimeStructUci, BLOCK_BASED_SCHEDULING)) { rangingTimeStructFlag.add( RangingTimeStructCapabilitiesFlag.HAS_BLOCK_BASED_SCHEDULING_SUPPORT); } builder.setRangingTimeStructCapabilities(rangingTimeStructFlag); byte schedulingModeUci = tlvs.getByte(SUPPORTED_SCHEDULED_MODE_VER_1_0); EnumSet schedulingModeFlag = EnumSet.noneOf(SchedulingModeCapabilitiesFlag.class); if (isBitSet(schedulingModeUci, CONTENTION_BASED_RANGING)) { schedulingModeFlag.add( SchedulingModeCapabilitiesFlag.HAS_CONTENTION_BASED_RANGING_SUPPORT); } if (isBitSet(schedulingModeUci, TIME_SCHEDULED_RANGING)) { schedulingModeFlag.add( SchedulingModeCapabilitiesFlag.HAS_TIME_SCHEDULED_RANGING_SUPPORT); } builder.setSchedulingModeCapabilities(schedulingModeFlag); byte ccConstraintLengthUci = tlvs.getByte(SUPPORTED_CC_CONSTRAINT_LENGTH_VER_1_0); EnumSet ccConstraintLengthFlag = EnumSet.noneOf(CcConstraintLengthCapabilitiesFlag.class); if (isBitSet(ccConstraintLengthUci, CONSTRAINT_LENGTH_3)) { ccConstraintLengthFlag.add( CcConstraintLengthCapabilitiesFlag.HAS_CONSTRAINT_LENGTH_3_SUPPORT); } if (isBitSet(ccConstraintLengthUci, CONSTRAINT_LENGTH_7)) { ccConstraintLengthFlag.add( CcConstraintLengthCapabilitiesFlag.HAS_CONSTRAINT_LENGTH_7_SUPPORT); } builder.setCcConstraintLengthCapabilities(ccConstraintLengthFlag); byte blockStridingUci = tlvs.getByte(SUPPORTED_BLOCK_STRIDING_VER_1_0); if (isBitSet(blockStridingUci, BLOCK_STRIDING)) { builder.hasBlockStridingSupport(true); } byte hoppingPreferenceUci = tlvs.getByte(SUPPORTED_HOPPING_MODE_VER_1_0); if (isBitSet(hoppingPreferenceUci, HOPPING_MODE)) { builder.hasHoppingPreferenceSupport(true); } byte extendedMacAddressUci = tlvs.getByte(SUPPORTED_EXTENDED_MAC_ADDRESS_VER_1_0); if (isBitSet(extendedMacAddressUci, EXTENDED_MAC_ADDRESS)) { builder.hasExtendedMacAddressSupport(true); } byte initiationTimeUci = tlvs.getByte(SUPPORTED_UWB_INITIATION_TIME_VER_1_0); if (isBitSet(initiationTimeUci, UWB_INITIATION_TIME)) { builder.hasInitiationTimeSupport(true); } byte channelsUci = tlvs.getByte(SUPPORTED_CHANNELS_VER_1_0); List channels = new ArrayList<>(); if (isBitSet(channelsUci, CHANNEL_5)) { channels.add(5); } if (isBitSet(channelsUci, CHANNEL_6)) { channels.add(6); } if (isBitSet(channelsUci, CHANNEL_8)) { channels.add(8); } if (isBitSet(channelsUci, CHANNEL_9)) { channels.add(9); } if (isBitSet(channelsUci, CHANNEL_10)) { channels.add(10); } if (isBitSet(channelsUci, CHANNEL_12)) { channels.add(12); } if (isBitSet(channelsUci, CHANNEL_13)) { channels.add(13); } if (isBitSet(channelsUci, CHANNEL_14)) { channels.add(14); } builder.setSupportedChannels(channels); byte rframeConfigUci = tlvs.getByte(SUPPORTED_RFRAME_CONFIG_VER_1_0); EnumSet rframeConfigFlag = EnumSet.noneOf(RframeCapabilityFlag.class); if (isBitSet(rframeConfigUci, SP0)) { rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP0_RFRAME_SUPPORT); } if (isBitSet(rframeConfigUci, SP1)) { rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP1_RFRAME_SUPPORT); } if (isBitSet(rframeConfigUci, SP3)) { rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP3_RFRAME_SUPPORT); } builder.setRframeCapabilities(rframeConfigFlag); byte bprfSets = tlvs.getByte(SUPPORTED_BPRF_PARAMETER_SETS_VER_1_0); int bprfSetsValue = Integer.valueOf(bprfSets); EnumSet bprfFlag; bprfFlag = FlagEnum.toEnumSet(bprfSetsValue, BprfParameterSetCapabilityFlag.values()); builder.setBprfParameterSetCapabilities(bprfFlag); byte[] hprfSets = tlvs.getByteArray(SUPPORTED_HPRF_PARAMETER_SETS_VER_1_0); // Extend the 5 bytes from HAL to 8 bytes for long. long hprfSetsValue = new BigInteger(TlvUtil.getReverseBytes(hprfSets)).longValue(); EnumSet hprfFlag; hprfFlag = FlagEnum.longToEnumSet( hprfSetsValue, HprfParameterSetCapabilityFlag.values()); builder.setHprfParameterSetCapabilities(hprfFlag); EnumSet prfFlag = EnumSet.noneOf(FiraParams.PrfCapabilityFlag.class); boolean hasBprfSupport = bprfSets != 0; if (hasBprfSupport) { prfFlag.add(FiraParams.PrfCapabilityFlag.HAS_BPRF_SUPPORT); } boolean hasHprfSupport = IntStream.range(0, hprfSets.length).parallel().anyMatch(i -> hprfSets[i] != 0); if (hasHprfSupport) { prfFlag.add(FiraParams.PrfCapabilityFlag.HAS_HPRF_SUPPORT); } builder.setPrfCapabilities(prfFlag); byte ccConstraintUci = tlvs.getByte(SUPPORTED_CC_CONSTRAINT_LENGTH_VER_1_0); EnumSet psduRateFlag = EnumSet.noneOf(PsduDataRateCapabilityFlag.class); if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K3) && hasBprfSupport) { psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_6M81_SUPPORT); } if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K7) && hasBprfSupport) { psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_7M80_SUPPORT); } if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K3) && hasHprfSupport) { psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_27M2_SUPPORT); } if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K7) && hasHprfSupport) { psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_31M2_SUPPORT); } builder.setPsduDataRateCapabilities(psduRateFlag); byte aoaUci = tlvs.getByte(SUPPORTED_AOA_VER_1_0); EnumSet aoaFlag = EnumSet.noneOf(FiraParams.AoaCapabilityFlag.class); if (isBitSet(aoaUci, AOA_AZIMUTH_90)) { aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_AZIMUTH_SUPPORT); } if (isBitSet(aoaUci, AOA_AZIMUTH_180)) { aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_FULL_AZIMUTH_SUPPORT); } if (isBitSet(aoaUci, AOA_ELEVATION)) { aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_ELEVATION_SUPPORT); } if (isBitSet(aoaUci, AOA_FOM)) { aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_FOM_SUPPORT); } byte aoaInterleavingUci = tlvs.getByte(SUPPORTED_AOA_RESULT_REQ_INTERLEAVING); if (isBitSet(aoaInterleavingUci, AOA_RESULT_REQ_INTERLEAVING)) { aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_INTERLEAVING_SUPPORT); } builder.setAoaCapabilities(aoaFlag); try { int maxMessageSizeUci = tlvs.getShort(SUPPORTED_MAX_MESSAGE_SIZE_VER_1_0); builder.setMaxMessageSize(Integer.valueOf(maxMessageSizeUci)); } catch (IllegalArgumentException e) { Log.w(TAG, "SUPPORTED_MAX_MESSAGE_SIZE not found."); } try { int maxDataPacketPayloadSizeUci = tlvs.getShort( SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE_VER_1_0); builder.setMaxDataPacketPayloadSize(Integer.valueOf(maxDataPacketPayloadSizeUci)); } catch (IllegalArgumentException e) { Log.w(TAG, "SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE not found."); } } else if (versionCheck.length == 4) { // FiRa Version 2.0 byte[] phyVersions = tlvs.getByteArray(SUPPORTED_FIRA_PHY_VERSION_RANGE_VER_2_0); builder.setMinPhyVersionSupported(FiraProtocolVersion.fromBytes(phyVersions, 0)); builder.setMaxPhyVersionSupported(FiraProtocolVersion.fromBytes(phyVersions, 2)); byte[] macVersions = tlvs.getByteArray(SUPPORTED_FIRA_MAC_VERSION_RANGE_VER_2_0); builder.setMinMacVersionSupported(FiraProtocolVersion.fromBytes(macVersions, 0)); builder.setMaxMacVersionSupported(FiraProtocolVersion.fromBytes(macVersions, 2)); byte[] deviceRolesUci = tlvs.getByteArray(SUPPORTED_DEVICE_ROLES_VER_2_0); EnumSet deviceRoles = EnumSet.noneOf(DeviceRoleCapabilityFlag.class); if (isBitSet(deviceRolesUci[0], INITIATOR)) { // This assumes both controller + controlee is supported. deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLLER_INITIATOR_SUPPORT); deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLEE_INITIATOR_SUPPORT); } if (isBitSet(deviceRolesUci[0], RESPONDER)) { // This assumes both controller + controlee is supported. deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLLER_RESPONDER_SUPPORT); deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLEE_RESPONDER_SUPPORT); } if (isBitSet(deviceRolesUci[0], UT_SYNCHRONIZATION_ANCHOR)) { deviceRoles.add(DeviceRoleCapabilityFlag.HAS_UT_SYNCHRONIZATION_SUPPORT); } if (isBitSet(deviceRolesUci[0], UT_ANCHOR)) { deviceRoles.add(DeviceRoleCapabilityFlag.HAS_UT_ANCHOR_SUPPORT); } if (isBitSet(deviceRolesUci[0], UT_TAG)) { deviceRoles.add(DeviceRoleCapabilityFlag.HAS_UT_TAG_SUPPORT); } if (isBitSet(deviceRolesUci[0], ADVERTISER)) { deviceRoles.add(DeviceRoleCapabilityFlag.HAS_ADVERTISER_SUPPORT); } if (isBitSet(deviceRolesUci[0], OBSERVER)) { deviceRoles.add(DeviceRoleCapabilityFlag.HAS_OBSERVER_SUPPORT); } if (isBitSet(deviceRolesUci[0], DT_ANCHOR)) { deviceRoles.add(DeviceRoleCapabilityFlag.HAS_DT_ANCHOR_SUPPORT); } if (isBitSet(deviceRolesUci[1], DT_TAG)) { deviceRoles.add(DeviceRoleCapabilityFlag.HAS_DT_TAG_SUPPORT); } builder.setDeviceRoleCapabilities(deviceRoles); byte[] rangingMethodUci = tlvs.getByteArray(SUPPORTED_RANGING_METHOD_VER_2_0); EnumSet rangingRoundFlag = EnumSet.noneOf( RangingRoundCapabilityFlag.class); if (isBitSet(rangingMethodUci[0], DS_TWR_DEFERRED)) { rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_DS_TWR_SUPPORT); } if (isBitSet(rangingMethodUci[0], SS_TWR_DEFERRED)) { rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_SS_TWR_SUPPORT); } if (isBitSet(rangingMethodUci[0], OWR_UL_TDOA)) { rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_OWR_UL_TDOA_SUPPORT); } if (isBitSet(rangingMethodUci[0], OWR_DL_TDOA)) { rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_OWR_DL_TDOA_SUPPORT); } if (isBitSet(rangingMethodUci[0], OWR_AOA)) { rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_OWR_AOA_SUPPORT); } if (isBitSet(rangingMethodUci[0], ESS_TWR_NON_DEFERRED)) { rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_ESS_TWR_SUPPORT); } if (isBitSet(rangingMethodUci[1], ADS_TWR)) { rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_ADS_TWR_SUPPORT); } builder.setRangingRoundCapabilities(rangingRoundFlag); // TODO(b/209053358): This does not align with UCI spec. if (isBitSet(rangingMethodUci[0], DS_TWR_NON_DEFERRED) || isBitSet(rangingMethodUci[0], SS_TWR_NON_DEFERRED)) { builder.hasNonDeferredModeSupport(true); } byte stsConfigUci = tlvs.getByte(SUPPORTED_STS_CONFIG_VER_2_0); EnumSet stsCapabilityFlag = EnumSet.noneOf(StsCapabilityFlag.class); if (isBitSet(stsConfigUci, STATIC_STS)) { stsCapabilityFlag.add(StsCapabilityFlag.HAS_STATIC_STS_SUPPORT); } if (isBitSet(stsConfigUci, DYNAMIC_STS)) { stsCapabilityFlag.add(StsCapabilityFlag.HAS_DYNAMIC_STS_SUPPORT); } if (isBitSet(stsConfigUci, DYNAMIC_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY)) { stsCapabilityFlag.add( StsCapabilityFlag.HAS_DYNAMIC_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT); } if (isBitSet(stsConfigUci, PROVISIONED_STS)) { stsCapabilityFlag.add(StsCapabilityFlag.HAS_PROVISIONED_STS_SUPPORT); } if (isBitSet(stsConfigUci, PROVISIONED_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY)) { stsCapabilityFlag.add( StsCapabilityFlag.HAS_PROVISIONED_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT); } builder.setStsCapabilities(stsCapabilityFlag); byte multiNodeUci = tlvs.getByte(SUPPORTED_MULTI_NODE_MODES_VER_2_0); EnumSet multiNodeFlag = EnumSet.noneOf(MultiNodeCapabilityFlag.class); if (isBitSet(multiNodeUci, UNICAST)) { multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_UNICAST_SUPPORT); } if (isBitSet(multiNodeUci, ONE_TO_MANY)) { multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_ONE_TO_MANY_SUPPORT); } if (isBitSet(multiNodeUci, MANY_TO_MANY)) { multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_MANY_TO_MANY_SUPPORT); } builder.setMultiNodeCapabilities(multiNodeFlag); byte rangingTimeStructUci = tlvs.getByte(SUPPORTED_RANGING_TIME_STRUCT_VER_2_0); EnumSet rangingTimeStructFlag = EnumSet.noneOf(RangingTimeStructCapabilitiesFlag.class); if (isBitSet(rangingTimeStructUci, BLOCK_BASED_SCHEDULING)) { rangingTimeStructFlag.add( RangingTimeStructCapabilitiesFlag.HAS_BLOCK_BASED_SCHEDULING_SUPPORT); } builder.setRangingTimeStructCapabilities(rangingTimeStructFlag); byte schedulingModeUci = tlvs.getByte(SUPPORTED_SCHEDULED_MODE_VER_2_0); EnumSet schedulingModeFlag = EnumSet.noneOf(SchedulingModeCapabilitiesFlag.class); if (isBitSet(schedulingModeUci, CONTENTION_BASED_RANGING)) { schedulingModeFlag.add( SchedulingModeCapabilitiesFlag.HAS_CONTENTION_BASED_RANGING_SUPPORT); } if (isBitSet(schedulingModeUci, TIME_SCHEDULED_RANGING)) { schedulingModeFlag.add( SchedulingModeCapabilitiesFlag.HAS_TIME_SCHEDULED_RANGING_SUPPORT); } builder.setSchedulingModeCapabilities(schedulingModeFlag); byte ccConstraintLengthUci = tlvs.getByte(SUPPORTED_CC_CONSTRAINT_LENGTH_VER_2_0); EnumSet ccConstraintLengthFlag = EnumSet.noneOf(CcConstraintLengthCapabilitiesFlag.class); if (isBitSet(ccConstraintLengthUci, CONSTRAINT_LENGTH_3)) { ccConstraintLengthFlag.add( CcConstraintLengthCapabilitiesFlag.HAS_CONSTRAINT_LENGTH_3_SUPPORT); } if (isBitSet(ccConstraintLengthUci, CONSTRAINT_LENGTH_7)) { ccConstraintLengthFlag.add( CcConstraintLengthCapabilitiesFlag.HAS_CONSTRAINT_LENGTH_7_SUPPORT); } builder.setCcConstraintLengthCapabilities(ccConstraintLengthFlag); byte blockStridingUci = tlvs.getByte(SUPPORTED_BLOCK_STRIDING_VER_2_0); if (isBitSet(blockStridingUci, BLOCK_STRIDING)) { builder.hasBlockStridingSupport(true); } byte hoppingPreferenceUci = tlvs.getByte(SUPPORTED_HOPPING_MODE_VER_2_0); if (isBitSet(hoppingPreferenceUci, HOPPING_MODE)) { builder.hasHoppingPreferenceSupport(true); } byte extendedMacAddressUci = tlvs.getByte(SUPPORTED_EXTENDED_MAC_ADDRESS_VER_2_0); if (isBitSet(extendedMacAddressUci, EXTENDED_MAC_ADDRESS)) { builder.hasExtendedMacAddressSupport(true); } byte initiationTimeUci = tlvs.getByte(SUPPORTED_UWB_INITIATION_TIME_VER_2_0); if (isBitSet(initiationTimeUci, UWB_INITIATION_TIME)) { builder.hasInitiationTimeSupport(true); } byte channelsUci = tlvs.getByte(SUPPORTED_CHANNELS_VER_2_0); List channels = new ArrayList<>(); if (isBitSet(channelsUci, CHANNEL_5)) { channels.add(5); } if (isBitSet(channelsUci, CHANNEL_6)) { channels.add(6); } if (isBitSet(channelsUci, CHANNEL_8)) { channels.add(8); } if (isBitSet(channelsUci, CHANNEL_9)) { channels.add(9); } if (isBitSet(channelsUci, CHANNEL_10)) { channels.add(10); } if (isBitSet(channelsUci, CHANNEL_12)) { channels.add(12); } if (isBitSet(channelsUci, CHANNEL_13)) { channels.add(13); } if (isBitSet(channelsUci, CHANNEL_14)) { channels.add(14); } builder.setSupportedChannels(channels); byte rframeConfigUci = tlvs.getByte(SUPPORTED_RFRAME_CONFIG_VER_2_0); EnumSet rframeConfigFlag = EnumSet.noneOf(RframeCapabilityFlag.class); if (isBitSet(rframeConfigUci, SP0)) { rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP0_RFRAME_SUPPORT); } if (isBitSet(rframeConfigUci, SP1)) { rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP1_RFRAME_SUPPORT); } if (isBitSet(rframeConfigUci, SP3)) { rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP3_RFRAME_SUPPORT); } builder.setRframeCapabilities(rframeConfigFlag); byte bprfSets = tlvs.getByte(SUPPORTED_BPRF_PARAMETER_SETS_VER_2_0); int bprfSetsValue = Integer.valueOf(bprfSets); EnumSet bprfFlag; bprfFlag = FlagEnum.toEnumSet(bprfSetsValue, BprfParameterSetCapabilityFlag.values()); builder.setBprfParameterSetCapabilities(bprfFlag); byte[] hprfSets = tlvs.getByteArray(SUPPORTED_HPRF_PARAMETER_SETS_VER_2_0); // Extend the 5 bytes from HAL to 8 bytes for long. long hprfSetsValue = new BigInteger(TlvUtil.getReverseBytes(hprfSets)).longValue(); EnumSet hprfFlag; hprfFlag = FlagEnum.longToEnumSet( hprfSetsValue, HprfParameterSetCapabilityFlag.values()); builder.setHprfParameterSetCapabilities(hprfFlag); EnumSet prfFlag = EnumSet.noneOf(FiraParams.PrfCapabilityFlag.class); boolean hasBprfSupport = bprfSets != 0; if (hasBprfSupport) { prfFlag.add(FiraParams.PrfCapabilityFlag.HAS_BPRF_SUPPORT); } boolean hasHprfSupport = IntStream.range(0, hprfSets.length).parallel().anyMatch(i -> hprfSets[i] != 0); if (hasHprfSupport) { prfFlag.add(FiraParams.PrfCapabilityFlag.HAS_HPRF_SUPPORT); } builder.setPrfCapabilities(prfFlag); byte ccConstraintUci = tlvs.getByte(SUPPORTED_CC_CONSTRAINT_LENGTH_VER_2_0); EnumSet psduRateFlag = EnumSet.noneOf(PsduDataRateCapabilityFlag.class); if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K3) && hasBprfSupport) { psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_6M81_SUPPORT); } if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K7) && hasBprfSupport) { psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_7M80_SUPPORT); } if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K3) && hasHprfSupport) { psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_27M2_SUPPORT); } if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K7) && hasHprfSupport) { psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_31M2_SUPPORT); } builder.setPsduDataRateCapabilities(psduRateFlag); byte aoaUci = tlvs.getByte(SUPPORTED_AOA_VER_2_0); EnumSet aoaFlag = EnumSet.noneOf(FiraParams.AoaCapabilityFlag.class); if (isBitSet(aoaUci, AOA_AZIMUTH_90)) { aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_AZIMUTH_SUPPORT); } if (isBitSet(aoaUci, AOA_AZIMUTH_180)) { aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_FULL_AZIMUTH_SUPPORT); } if (isBitSet(aoaUci, AOA_ELEVATION)) { aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_ELEVATION_SUPPORT); } if (isBitSet(aoaUci, AOA_FOM)) { aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_FOM_SUPPORT); } byte aoaInterleavingUci = tlvs.getByte(SUPPORTED_AOA_RESULT_REQ_INTERLEAVING); if (isBitSet(aoaInterleavingUci, AOA_RESULT_REQ_INTERLEAVING)) { aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_INTERLEAVING_SUPPORT); } builder.setAoaCapabilities(aoaFlag); try { int maxMessageSizeUci = tlvs.getShort(SUPPORTED_MAX_MESSAGE_SIZE_VER_2_0); builder.setMaxMessageSize(Integer.valueOf(maxMessageSizeUci)); } catch (IllegalArgumentException e) { Log.w(TAG, "SUPPORTED_MAX_MESSAGE_SIZE not found."); } try { int maxDataPacketPayloadSizeUci = tlvs.getShort( SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE_VER_2_0); builder.setMaxDataPacketPayloadSize(Integer.valueOf(maxDataPacketPayloadSizeUci)); } catch (IllegalArgumentException e) { Log.w(TAG, "SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE not found."); } int deviceType = tlvs.getByte(SUPPORTED_DEVICE_TYPE_VER_2_0); builder.setDeviceType(deviceType); int supportedSuspendSupport = tlvs.getByte(SUPPORTED_SUSPEND_RANGING_VER_2_0); builder.setSuspendRangingSupport(supportedSuspendSupport != 0); int sessionKeyLength = tlvs.getByte(SUPPORTED_SESSION_KEY_LENGTH_VER_2_0); builder.setSessionKeyLength(sessionKeyLength); try { int dtTagMaxActiveRr = tlvs.getByte(SUPPORTED_DT_TAG_MAX_ACTIVE_RR_2_0); builder.setDtTagMaxActiveRr(dtTagMaxActiveRr); } catch (IllegalArgumentException e) { Log.w(TAG, "SUPPORTED_DT_TAG_MAX_ACTIVE_RR not found."); } try { byte dtTagBlockSkippingUci = tlvs.getByte(SUPPORTED_DT_TAG_BLOCK_SKIPPING_2_0); if (isBitSet(dtTagBlockSkippingUci, DT_TAG_BLOCK_SKIPPING)) { builder.setDtTagBlockSkippingSupport(true); } } catch (IllegalArgumentException e) { Log.w(TAG, "SUPPORTED_DT_TAG_BLOCK_SKIPPING_2_0 not found."); } try { byte psduLengthUci = tlvs.getByte(SUPPORTED_PSDU_LENGTH_2_0); if (isBitSet(psduLengthUci, PSDU_LENGTH_SUPPORT)) { builder.setPsduLengthSupport(true); } } catch (IllegalArgumentException e) { Log.w(TAG, "SUPPORTED_PSDU_LENGTH_2_0 not found."); } } else { // This FiRa version is not supported yet. return null; } try { int minRangingInterval = tlvs.getInt(SUPPORTED_MIN_RANGING_INTERVAL_MS); builder.setMinRangingIntervalSupported(minRangingInterval); } catch (IllegalArgumentException e) { Log.w(TAG, "SUPPORTED_MIN_RANGING_INTERVAL_MS not found."); } try { int minSlotDurationUs = TlvUtil.rstuToUs(tlvs.getInt(SUPPORTED_MIN_SLOT_DURATION_RSTU)); builder.setMinSlotDurationSupportedUs(minSlotDurationUs); } catch (IllegalArgumentException e) { Log.w(TAG, "SUPPORTED_MIN_SLOT_DURATION not found."); } try { int maxRangingSessionNumber = tlvs.getInt(SUPPORTED_MAX_RANGING_SESSION_NUMBER); builder.setMaxRangingSessionNumberSupported(maxRangingSessionNumber); } catch (IllegalArgumentException e) { Log.w(TAG, "SUPPORTED_MAX_RANGING_SESSION_NUMBER not found"); } try { byte rssiReporting = tlvs.getByte(SUPPORTED_RSSI_REPORTING); if (isBitSet(rssiReporting, RSSI_REPORTING)) { builder.hasRssiReportingSupport(true); } } catch (IllegalArgumentException e) { Log.w(TAG, "SUPPORTED_RSSI_REPORTING not found."); } try { byte diagnostics = tlvs.getByte(SUPPORTED_DIAGNOSTICS); if (isBitSet(diagnostics, DIAGNOSTICS)) { builder.hasDiagnosticsSupport(true); } } catch (IllegalArgumentException e) { Log.w(TAG, "SUPPORTED_DIAGNOSTICS not found."); } try { byte[] rangeDataNtfConfigUciBytes = tlvs.getByteArray(SUPPORTED_RANGE_DATA_NTF_CONFIG); int rangeDataNtfConfigUci = new BigInteger(TlvUtil.getReverseBytes(rangeDataNtfConfigUciBytes)).intValue(); EnumSet rangeDataNtfConfigCapabilityFlag = EnumSet.noneOf(FiraParams.RangeDataNtfConfigCapabilityFlag.class); if (isBitSet(rangeDataNtfConfigUci, RANGE_DATA_NTF_CONFIG_ENABLE)) { rangeDataNtfConfigCapabilityFlag.add( FiraParams.RangeDataNtfConfigCapabilityFlag .HAS_RANGE_DATA_NTF_CONFIG_ENABLE); } if (isBitSet(rangeDataNtfConfigUci, RANGE_DATA_NTF_CONFIG_DISABLE)) { rangeDataNtfConfigCapabilityFlag.add( FiraParams.RangeDataNtfConfigCapabilityFlag .HAS_RANGE_DATA_NTF_CONFIG_DISABLE); } if (isBitSet(rangeDataNtfConfigUci, RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_LEVEL_TRIG)) { rangeDataNtfConfigCapabilityFlag.add( FiraParams.RangeDataNtfConfigCapabilityFlag .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_LEVEL_TRIG); } if (isBitSet(rangeDataNtfConfigUci, RANGE_DATA_NTF_CONFIG_ENABLE_AOA_LEVEL_TRIG)) { rangeDataNtfConfigCapabilityFlag.add( FiraParams.RangeDataNtfConfigCapabilityFlag .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_AOA_LEVEL_TRIG); } if (isBitSet(rangeDataNtfConfigUci, RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_LEVEL_TRIG)) { rangeDataNtfConfigCapabilityFlag.add( FiraParams.RangeDataNtfConfigCapabilityFlag .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_LEVEL_TRIG); } if (isBitSet(rangeDataNtfConfigUci, RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_EDGE_TRIG)) { rangeDataNtfConfigCapabilityFlag.add( FiraParams.RangeDataNtfConfigCapabilityFlag .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_EDGE_TRIG); } if (isBitSet(rangeDataNtfConfigUci, RANGE_DATA_NTF_CONFIG_ENABLE_AOA_EDGE_TRIG)) { rangeDataNtfConfigCapabilityFlag.add( FiraParams.RangeDataNtfConfigCapabilityFlag .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_AOA_EDGE_TRIG); } if (isBitSet(rangeDataNtfConfigUci, RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_EDGE_TRIG)) { rangeDataNtfConfigCapabilityFlag.add( FiraParams.RangeDataNtfConfigCapabilityFlag .HAS_RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_EDGE_TRIG); } builder.setRangeDataNtfConfigCapabilities(rangeDataNtfConfigCapabilityFlag); } catch (IllegalArgumentException e) { Log.w(TAG, "SUPPORTED_RANGE_DATA_NTF_CONFIG not found."); } return builder.build(); } }