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.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.AOA_RESULT_REQ_INTERLEAVING; 24 import static com.android.server.uwb.config.CapabilityParam.BLOCK_STRIDING; 25 import static com.android.server.uwb.config.CapabilityParam.CC_CONSTRAINT_LENGTH_K3; 26 import static com.android.server.uwb.config.CapabilityParam.CC_CONSTRAINT_LENGTH_K7; 27 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_10; 28 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_12; 29 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_13; 30 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_14; 31 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_5; 32 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_6; 33 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_8; 34 import static com.android.server.uwb.config.CapabilityParam.CHANNEL_9; 35 import static com.android.server.uwb.config.CapabilityParam.DS_TWR_DEFERRED; 36 import static com.android.server.uwb.config.CapabilityParam.DS_TWR_NON_DEFERRED; 37 import static com.android.server.uwb.config.CapabilityParam.DYNAMIC_STS; 38 import static com.android.server.uwb.config.CapabilityParam.DYNAMIC_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY; 39 import static com.android.server.uwb.config.CapabilityParam.INITIATOR; 40 import static com.android.server.uwb.config.CapabilityParam.MANY_TO_MANY; 41 import static com.android.server.uwb.config.CapabilityParam.ONE_TO_MANY; 42 import static com.android.server.uwb.config.CapabilityParam.RESPONDER; 43 import static com.android.server.uwb.config.CapabilityParam.SP0; 44 import static com.android.server.uwb.config.CapabilityParam.SP1; 45 import static com.android.server.uwb.config.CapabilityParam.SP3; 46 import static com.android.server.uwb.config.CapabilityParam.SS_TWR_DEFERRED; 47 import static com.android.server.uwb.config.CapabilityParam.SS_TWR_NON_DEFERRED; 48 import static com.android.server.uwb.config.CapabilityParam.STATIC_STS; 49 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_AOA; 50 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_AOA_RESULT_REQ_INTERLEAVING; 51 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_BLOCK_STRIDING; 52 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_BPRF_PARAMETER_SETS; 53 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_CC_CONSTRAINT_LENGTH; 54 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_CHANNELS; 55 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_DEVICE_ROLES; 56 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_EXTENDED_MAC_ADDRESS; 57 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_FIRA_MAC_VERSION_RANGE; 58 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_FIRA_PHY_VERSION_RANGE; 59 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_HPRF_PARAMETER_SETS; 60 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_MULTI_NODE_MODES; 61 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RANGING_METHOD; 62 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_RFRAME_CONFIG; 63 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_STS_CONFIG; 64 import static com.android.server.uwb.config.CapabilityParam.SUPPORTED_UWB_INITIATION_TIME; 65 import static com.android.server.uwb.config.CapabilityParam.UNICAST; 66 import static com.android.server.uwb.config.CapabilityParam.UWB_INITIATION_TIME; 67 68 import com.google.uwb.support.base.FlagEnum; 69 import com.google.uwb.support.base.Params; 70 import com.google.uwb.support.fira.FiraParams; 71 import com.google.uwb.support.fira.FiraParams.BprfParameterSetCapabilityFlag; 72 import com.google.uwb.support.fira.FiraParams.DeviceRoleCapabilityFlag; 73 import com.google.uwb.support.fira.FiraParams.HprfParameterSetCapabilityFlag; 74 import com.google.uwb.support.fira.FiraParams.MultiNodeCapabilityFlag; 75 import com.google.uwb.support.fira.FiraParams.PsduDataRateCapabilityFlag; 76 import com.google.uwb.support.fira.FiraParams.RangingRoundCapabilityFlag; 77 import com.google.uwb.support.fira.FiraParams.RframeCapabilityFlag; 78 import com.google.uwb.support.fira.FiraParams.StsCapabilityFlag; 79 import com.google.uwb.support.fira.FiraProtocolVersion; 80 import com.google.uwb.support.fira.FiraSpecificationParams; 81 82 import java.math.BigInteger; 83 import java.util.ArrayList; 84 import java.util.EnumSet; 85 import java.util.List; 86 import java.util.stream.IntStream; 87 88 public class FiraDecoder extends TlvDecoder { 89 @Override getParams(TlvDecoderBuffer tlvs, Class<T> paramType)90 public <T extends Params> T getParams(TlvDecoderBuffer tlvs, Class<T> paramType) { 91 if (FiraSpecificationParams.class.equals(paramType)) { 92 return (T) getFiraSpecificationParamsFromTlvBuffer(tlvs); 93 } 94 return null; 95 } 96 isBitSet(int flags, int mask)97 private static boolean isBitSet(int flags, int mask) { 98 return (flags & mask) != 0; 99 } 100 getFiraSpecificationParamsFromTlvBuffer(TlvDecoderBuffer tlvs)101 private FiraSpecificationParams getFiraSpecificationParamsFromTlvBuffer(TlvDecoderBuffer tlvs) { 102 FiraSpecificationParams.Builder builder = new FiraSpecificationParams.Builder(); 103 byte[] phyVersions = tlvs.getByteArray(SUPPORTED_FIRA_PHY_VERSION_RANGE); 104 builder.setMinPhyVersionSupported(FiraProtocolVersion.fromBytes(phyVersions, 0)); 105 builder.setMaxPhyVersionSupported(FiraProtocolVersion.fromBytes(phyVersions, 2)); 106 byte[] macVersions = tlvs.getByteArray(SUPPORTED_FIRA_MAC_VERSION_RANGE); 107 builder.setMinMacVersionSupported(FiraProtocolVersion.fromBytes(macVersions, 0)); 108 builder.setMaxMacVersionSupported(FiraProtocolVersion.fromBytes(macVersions, 2)); 109 110 byte deviceRolesUci = tlvs.getByte(SUPPORTED_DEVICE_ROLES); 111 EnumSet<DeviceRoleCapabilityFlag> deviceRoles = 112 EnumSet.noneOf(DeviceRoleCapabilityFlag.class); 113 if (isBitSet(deviceRolesUci, INITIATOR)) { 114 // This assumes both controller + controlee is supported. 115 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLLER_INITIATOR_SUPPORT); 116 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLEE_INITIATOR_SUPPORT); 117 } 118 if (isBitSet(deviceRolesUci, RESPONDER)) { 119 // This assumes both controller + controlee is supported. 120 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLLER_RESPONDER_SUPPORT); 121 deviceRoles.add(DeviceRoleCapabilityFlag.HAS_CONTROLEE_RESPONDER_SUPPORT); 122 } 123 builder.setDeviceRoleCapabilities(deviceRoles); 124 125 byte rangingMethodUci = tlvs.getByte(SUPPORTED_RANGING_METHOD); 126 EnumSet<RangingRoundCapabilityFlag> rangingRoundFlag = EnumSet.noneOf( 127 RangingRoundCapabilityFlag.class); 128 if (isBitSet(rangingMethodUci, DS_TWR_DEFERRED)) { 129 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_DS_TWR_SUPPORT); 130 } 131 if (isBitSet(rangingMethodUci, SS_TWR_DEFERRED)) { 132 rangingRoundFlag.add(RangingRoundCapabilityFlag.HAS_SS_TWR_SUPPORT); 133 } 134 builder.setRangingRoundCapabilities(rangingRoundFlag); 135 136 // TODO(b/209053358): This does not align with UCI spec. 137 if (isBitSet(rangingMethodUci, DS_TWR_NON_DEFERRED) 138 || isBitSet(rangingMethodUci, SS_TWR_NON_DEFERRED)) { 139 builder.hasNonDeferredModeSupport(true); 140 } 141 142 byte stsConfigUci = tlvs.getByte(SUPPORTED_STS_CONFIG); 143 EnumSet<StsCapabilityFlag> stsCapabilityFlag = EnumSet.noneOf(StsCapabilityFlag.class); 144 if (isBitSet(stsConfigUci, STATIC_STS)) { 145 stsCapabilityFlag.add(StsCapabilityFlag.HAS_STATIC_STS_SUPPORT); 146 } 147 if (isBitSet(stsConfigUci, DYNAMIC_STS)) { 148 stsCapabilityFlag.add(StsCapabilityFlag.HAS_DYNAMIC_STS_SUPPORT); 149 } 150 if (isBitSet(stsConfigUci, DYNAMIC_STS_RESPONDER_SPECIFIC_SUBSESSION_KEY)) { 151 stsCapabilityFlag.add( 152 StsCapabilityFlag.HAS_DYNAMIC_STS_INDIVIDUAL_CONTROLEE_KEY_SUPPORT); 153 } 154 builder.setStsCapabilities(stsCapabilityFlag); 155 156 byte multiNodeUci = tlvs.getByte(SUPPORTED_MULTI_NODE_MODES); 157 EnumSet<MultiNodeCapabilityFlag> multiNodeFlag = 158 EnumSet.noneOf(MultiNodeCapabilityFlag.class); 159 if (isBitSet(multiNodeUci, UNICAST)) { 160 multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_UNICAST_SUPPORT); 161 } 162 if (isBitSet(multiNodeUci, ONE_TO_MANY)) { 163 multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_ONE_TO_MANY_SUPPORT); 164 } 165 if (isBitSet(multiNodeUci, MANY_TO_MANY)) { 166 multiNodeFlag.add(MultiNodeCapabilityFlag.HAS_MANY_TO_MANY_SUPPORT); 167 } 168 builder.setMultiNodeCapabilities(multiNodeFlag); 169 170 byte blockStridingUci = tlvs.getByte(SUPPORTED_BLOCK_STRIDING); 171 if (isBitSet(blockStridingUci, BLOCK_STRIDING)) { 172 builder.hasBlockStridingSupport(true); 173 } 174 175 byte initiationTimeUci = tlvs.getByte(SUPPORTED_UWB_INITIATION_TIME); 176 if (isBitSet(initiationTimeUci, UWB_INITIATION_TIME)) { 177 builder.hasInitiationTimeSupport(true); 178 } 179 180 byte channelsUci = tlvs.getByte(SUPPORTED_CHANNELS); 181 List<Integer> channels = new ArrayList<>(); 182 if (isBitSet(channelsUci, CHANNEL_5)) { 183 channels.add(5); 184 } 185 if (isBitSet(channelsUci, CHANNEL_6)) { 186 channels.add(6); 187 } 188 if (isBitSet(channelsUci, CHANNEL_8)) { 189 channels.add(8); 190 } 191 if (isBitSet(channelsUci, CHANNEL_9)) { 192 channels.add(9); 193 } 194 if (isBitSet(channelsUci, CHANNEL_10)) { 195 channels.add(10); 196 } 197 if (isBitSet(channelsUci, CHANNEL_12)) { 198 channels.add(12); 199 } 200 if (isBitSet(channelsUci, CHANNEL_13)) { 201 channels.add(13); 202 } 203 if (isBitSet(channelsUci, CHANNEL_14)) { 204 channels.add(14); 205 } 206 builder.setSupportedChannels(channels); 207 208 byte rframeConfigUci = tlvs.getByte(SUPPORTED_RFRAME_CONFIG); 209 EnumSet<RframeCapabilityFlag> rframeConfigFlag = 210 EnumSet.noneOf(RframeCapabilityFlag.class); 211 if (isBitSet(rframeConfigUci, SP0)) { 212 rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP0_RFRAME_SUPPORT); 213 } 214 if (isBitSet(rframeConfigUci, SP1)) { 215 rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP1_RFRAME_SUPPORT); 216 } 217 if (isBitSet(rframeConfigUci, SP3)) { 218 rframeConfigFlag.add(RframeCapabilityFlag.HAS_SP3_RFRAME_SUPPORT); 219 } 220 builder.setRframeCapabilities(rframeConfigFlag); 221 222 byte bprfSets = tlvs.getByte(SUPPORTED_BPRF_PARAMETER_SETS); 223 int bprfSetsValue = Integer.valueOf(bprfSets); 224 EnumSet<BprfParameterSetCapabilityFlag> bprfFlag; 225 bprfFlag = FlagEnum.toEnumSet(bprfSetsValue, BprfParameterSetCapabilityFlag.values()); 226 builder.setBprfParameterSetCapabilities(bprfFlag); 227 228 byte[] hprfSets = tlvs.getByteArray(SUPPORTED_HPRF_PARAMETER_SETS); 229 // Extend the 5 bytes from HAL to 8 bytes for long. 230 long hprfSetsValue = new BigInteger(hprfSets).longValue(); 231 EnumSet<HprfParameterSetCapabilityFlag> hprfFlag; 232 hprfFlag = FlagEnum.longToEnumSet( 233 hprfSetsValue, HprfParameterSetCapabilityFlag.values()); 234 builder.setHprfParameterSetCapabilities(hprfFlag); 235 236 EnumSet<FiraParams.PrfCapabilityFlag> prfFlag = 237 EnumSet.noneOf(FiraParams.PrfCapabilityFlag.class); 238 boolean hasBprfSupport = bprfSets != 0; 239 if (hasBprfSupport) { 240 prfFlag.add(FiraParams.PrfCapabilityFlag.HAS_BPRF_SUPPORT); 241 } 242 boolean hasHprfSupport = 243 IntStream.range(0, hprfSets.length).parallel().anyMatch(i -> hprfSets[i] != 0); 244 if (hasHprfSupport) { 245 prfFlag.add(FiraParams.PrfCapabilityFlag.HAS_HPRF_SUPPORT); 246 } 247 builder.setPrfCapabilities(prfFlag); 248 249 byte ccConstraintUci = tlvs.getByte(SUPPORTED_CC_CONSTRAINT_LENGTH); 250 EnumSet<PsduDataRateCapabilityFlag> psduRateFlag = 251 EnumSet.noneOf(PsduDataRateCapabilityFlag.class); 252 if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K3) && hasBprfSupport) { 253 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_6M81_SUPPORT); 254 } 255 if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K7) && hasBprfSupport) { 256 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_7M80_SUPPORT); 257 } 258 if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K3) && hasHprfSupport) { 259 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_27M2_SUPPORT); 260 } 261 if (isBitSet(ccConstraintUci, CC_CONSTRAINT_LENGTH_K7) && hasHprfSupport) { 262 psduRateFlag.add(PsduDataRateCapabilityFlag.HAS_31M2_SUPPORT); 263 } 264 builder.setPsduDataRateCapabilities(psduRateFlag); 265 266 byte aoaUci = tlvs.getByte(SUPPORTED_AOA); 267 EnumSet<FiraParams.AoaCapabilityFlag> aoaFlag = 268 EnumSet.noneOf(FiraParams.AoaCapabilityFlag.class); 269 if (isBitSet(aoaUci, AOA_AZIMUTH_90)) { 270 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_AZIMUTH_SUPPORT); 271 } 272 if (isBitSet(aoaUci, AOA_AZIMUTH_180)) { 273 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_FULL_AZIMUTH_SUPPORT); 274 } 275 if (isBitSet(aoaUci, AOA_ELEVATION)) { 276 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_ELEVATION_SUPPORT); 277 } 278 if (isBitSet(aoaUci, AOA_FOM)) { 279 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_FOM_SUPPORT); 280 } 281 byte aoaInterleavingUci = tlvs.getByte(SUPPORTED_AOA_RESULT_REQ_INTERLEAVING); 282 if (isBitSet(aoaInterleavingUci, AOA_RESULT_REQ_INTERLEAVING)) { 283 aoaFlag.add(FiraParams.AoaCapabilityFlag.HAS_INTERLEAVING_SUPPORT); 284 } 285 builder.setAoaCapabilities(aoaFlag); 286 287 // TODO(b/209053358): This is not present in the FiraSpecificationParams. 288 byte extendedMacUci = tlvs.getByte(SUPPORTED_EXTENDED_MAC_ADDRESS); 289 return builder.build(); 290 } 291 } 292