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.google.uwb.support.fira.FiraParams.RANGE_DATA_NTF_CONFIG_ENABLE_AOA_EDGE_TRIG; 20 import static com.google.uwb.support.fira.FiraParams.RANGE_DATA_NTF_CONFIG_ENABLE_AOA_LEVEL_TRIG; 21 import static com.google.uwb.support.fira.FiraParams.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_EDGE_TRIG; 22 import static com.google.uwb.support.fira.FiraParams.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_LEVEL_TRIG; 23 24 import android.uwb.UwbAddress; 25 26 import com.android.modules.utils.build.SdkLevel; 27 import com.android.server.uwb.config.ConfigParam; 28 import com.android.server.uwb.util.UwbUtil; 29 30 import com.google.uwb.support.base.Params; 31 import com.google.uwb.support.fira.FiraOpenSessionParams; 32 import com.google.uwb.support.fira.FiraParams; 33 import com.google.uwb.support.fira.FiraRangingReconfigureParams; 34 35 import java.nio.ByteBuffer; 36 import java.util.Arrays; 37 38 public class FiraEncoder extends TlvEncoder { 39 @Override getTlvBuffer(Params param)40 public TlvBuffer getTlvBuffer(Params param) { 41 if (param instanceof FiraOpenSessionParams) { 42 return getTlvBufferFromFiraOpenSessionParams(param); 43 } 44 45 if (param instanceof FiraRangingReconfigureParams) { 46 return getTlvBufferFromFiraRangingReconfigureParams(param); 47 } 48 return null; 49 } 50 hasAoaBoundInRangeDataNtfConfig(int rangeDataNtfConfig)51 private static boolean hasAoaBoundInRangeDataNtfConfig(int rangeDataNtfConfig) { 52 return rangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_AOA_LEVEL_TRIG 53 || rangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_LEVEL_TRIG 54 || rangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_AOA_EDGE_TRIG 55 || rangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_EDGE_TRIG; 56 } 57 getTlvBufferFromFiraOpenSessionParams(Params baseParam)58 private TlvBuffer getTlvBufferFromFiraOpenSessionParams(Params baseParam) { 59 FiraOpenSessionParams params = (FiraOpenSessionParams) baseParam; 60 int stsConfig = params.getStsConfig(); 61 int deviceType = params.getDeviceType(); 62 int resultReportConfig = getResultReportConfig(params); 63 int rangingRoundControl = getRangingRoundControl(params); 64 int deviceRole = params.getDeviceRole(); 65 66 TlvBuffer.Builder tlvBufferBuilder = new TlvBuffer.Builder(); 67 if (deviceRole != FiraParams.RANGING_DEVICE_DT_TAG) { 68 ByteBuffer dstAddressList = ByteBuffer.allocate(1024); 69 for (UwbAddress address : params.getDestAddressList()) { 70 dstAddressList.put(getComputedMacAddress(address)); 71 } 72 tlvBufferBuilder.putByte(ConfigParam.DEVICE_TYPE, (byte) params.getDeviceType()) 73 .putByte(ConfigParam.NUMBER_OF_CONTROLEES, 74 (byte) params.getDestAddressList().size()); 75 if (params.getDestAddressList().size() > 0) { 76 tlvBufferBuilder.putByteArray( 77 ConfigParam.DST_MAC_ADDRESS, dstAddressList.position(), 78 Arrays.copyOf(dstAddressList.array(), dstAddressList.position())); 79 } 80 } 81 tlvBufferBuilder.putByte(ConfigParam.RANGING_ROUND_USAGE, 82 (byte) params.getRangingRoundUsage()) 83 .putByte(ConfigParam.STS_CONFIG, (byte) params.getStsConfig()) 84 .putByte(ConfigParam.MULTI_NODE_MODE, (byte) params.getMultiNodeMode()) 85 .putByte(ConfigParam.CHANNEL_NUMBER, (byte) params.getChannelNumber()) 86 .putByteArray(ConfigParam.DEVICE_MAC_ADDRESS, params.getDeviceAddress().size(), 87 getComputedMacAddress(params.getDeviceAddress())) 88 .putShort(ConfigParam.SLOT_DURATION, (short) params.getSlotDurationRstu()) 89 .putByte(ConfigParam.MAC_FCS_TYPE, (byte) params.getFcsType()) 90 .putByte(ConfigParam.RANGING_ROUND_CONTROL, 91 (byte) rangingRoundControl/* params.getMeasurementReportType()*/) 92 .putByte(ConfigParam.AOA_RESULT_REQ, (byte) params.getAoaResultRequest()) 93 .putByte(ConfigParam.RANGE_DATA_NTF_CONFIG, (byte) params.getRangeDataNtfConfig()) 94 .putShort(ConfigParam.RANGE_DATA_NTF_PROXIMITY_NEAR, 95 (short) params.getRangeDataNtfProximityNear()) 96 .putShort(ConfigParam.RANGE_DATA_NTF_PROXIMITY_FAR, 97 (short) params.getRangeDataNtfProximityFar()) 98 .putByte(ConfigParam.DEVICE_ROLE, (byte) params.getDeviceRole()) 99 .putByte(ConfigParam.RFRAME_CONFIG, (byte) params.getRframeConfig()) 100 .putByte(ConfigParam.RSSI_REPORTING, 101 (byte) (params.isRssiReportingEnabled() ? 1 : 0)) 102 .putByte(ConfigParam.PREAMBLE_CODE_INDEX, (byte) params.getPreambleCodeIndex()) 103 .putByte(ConfigParam.SFD_ID, (byte) params.getSfdId()) 104 .putByte(ConfigParam.PSDU_DATA_RATE, (byte) params.getPsduDataRate()) 105 .putByte(ConfigParam.PREAMBLE_DURATION, (byte) params.getPreambleDuration()) 106 // n.a. for OWR UL-TDoA and 0x01 for all other RangingRoundUsage values. 107 .putByte(ConfigParam.RANGING_TIME_STRUCT, (byte) 0x01) 108 .putByte(ConfigParam.SLOTS_PER_RR, (byte) params.getSlotsPerRangingRound()) 109 .putByte(ConfigParam.TX_ADAPTIVE_PAYLOAD_POWER, 110 params.isTxAdaptivePayloadPowerEnabled() ? (byte) 1 : (byte) 0) 111 .putByte(ConfigParam.PRF_MODE, (byte) params.getPrfMode()) 112 .putByte(ConfigParam.SCHEDULED_MODE, (byte) params.getScheduledMode()) 113 .putByte(ConfigParam.KEY_ROTATION, 114 params.isKeyRotationEnabled() ? (byte) 1 : (byte) 0) 115 .putByte(ConfigParam.KEY_ROTATION_RATE, (byte) params.getKeyRotationRate()) 116 .putByte(ConfigParam.SESSION_PRIORITY, (byte) params.getSessionPriority()) 117 .putByte(ConfigParam.MAC_ADDRESS_MODE, (byte) params.getMacAddressMode()) 118 .putByte(ConfigParam.NUMBER_OF_STS_SEGMENTS, (byte) params.getStsSegmentCount()) 119 .putShort(ConfigParam.MAX_RR_RETRY, (short) params.getMaxRangingRoundRetries()) 120 .putByte(ConfigParam.HOPPING_MODE, 121 (byte) params.getHoppingMode()) 122 .putByte(ConfigParam.BLOCK_STRIDE_LENGTH, (byte) params.getBlockStrideLength()) 123 .putByte(ConfigParam.RESULT_REPORT_CONFIG, (byte) resultReportConfig) 124 .putByte(ConfigParam.IN_BAND_TERMINATION_ATTEMPT_COUNT, 125 (byte) params.getInBandTerminationAttemptCount()) 126 .putByte(ConfigParam.BPRF_PHR_DATA_RATE, 127 (byte) params.getBprfPhrDataRate()) 128 .putShort(ConfigParam.MAX_NUMBER_OF_MEASUREMENTS, 129 (short) params.getMaxNumberOfMeasurements()) 130 .putByte(ConfigParam.STS_LENGTH, (byte) params.getStsLength()); 131 if (params.getDeviceRole() != FiraParams.RANGING_DEVICE_UT_TAG) { 132 tlvBufferBuilder.putInt(ConfigParam.RANGING_INTERVAL, params.getRangingIntervalMs()); 133 } 134 if (params.getProtocolVersion().getMajor() >= 2) { 135 // Initiation time Changed from 4 byte field to 8 byte field in version 2. 136 if (deviceRole != FiraParams.RANGING_DEVICE_DT_TAG) { 137 tlvBufferBuilder.putLong(ConfigParam.UWB_INITIATION_TIME, 138 params.getInitiationTime()); 139 } 140 tlvBufferBuilder.putByte(ConfigParam.LINK_LAYER_MODE, (byte) params.getLinkLayerMode()); 141 } else { 142 if (deviceRole != FiraParams.RANGING_DEVICE_DT_TAG) { 143 tlvBufferBuilder.putInt(ConfigParam.UWB_INITIATION_TIME, 144 Math.toIntExact(params.getInitiationTime())); 145 } 146 } 147 if ((stsConfig == FiraParams.STS_CONFIG_DYNAMIC_FOR_CONTROLEE_INDIVIDUAL_KEY) 148 && (deviceType == FiraParams.RANGING_DEVICE_TYPE_CONTROLEE)) { 149 tlvBufferBuilder.putInt(ConfigParam.SUB_SESSION_ID, params.getSubSessionId()); 150 } 151 if (stsConfig == FiraParams.STS_CONFIG_STATIC) { 152 tlvBufferBuilder 153 .putByteArray(ConfigParam.VENDOR_ID, params.getVendorId() != null 154 ? getComputedVendorId(params.getVendorId()) 155 : null) 156 .putByteArray(ConfigParam.STATIC_STS_IV, params.getStaticStsIV()); 157 } else if ((stsConfig == FiraParams.STS_CONFIG_PROVISIONED) 158 || (stsConfig 159 == FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY)) { 160 tlvBufferBuilder.putByteArray(ConfigParam.SESSION_KEY, params.getSessionKey()); 161 if (stsConfig 162 == FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY 163 && (deviceType == FiraParams.RANGING_DEVICE_TYPE_CONTROLEE)) { 164 tlvBufferBuilder.putInt(ConfigParam.SUB_SESSION_ID, params.getSubSessionId()); 165 tlvBufferBuilder.putByteArray(ConfigParam.SUBSESSION_KEY, 166 params.getSubsessionKey()); 167 } 168 } 169 if (params.getAoaResultRequest() 170 == FiraParams.AOA_RESULT_REQUEST_MODE_REQ_AOA_RESULTS_INTERLEAVED) { 171 tlvBufferBuilder.putByte(ConfigParam.NUM_RANGE_MEASUREMENTS, 172 (byte) params.getNumOfMsrmtFocusOnRange()) 173 .putByte(ConfigParam.NUM_AOA_AZIMUTH_MEASUREMENTS, 174 (byte) params.getNumOfMsrmtFocusOnAoaAzimuth()) 175 .putByte(ConfigParam.NUM_AOA_ELEVATION_MEASUREMENTS, 176 (byte) params.getNumOfMsrmtFocusOnAoaElevation()); 177 } 178 if (hasAoaBoundInRangeDataNtfConfig(params.getRangeDataNtfConfig())) { 179 tlvBufferBuilder.putShortArray(ConfigParam.RANGE_DATA_NTF_AOA_BOUND, new short[]{ 180 // TODO (b/235355249): Verify this conversion. This is using AOA value 181 // in UwbTwoWayMeasurement to external RangingMeasurement conversion as 182 // reference. 183 (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat( 184 UwbUtil.radianTodegree( 185 params.getRangeDataNtfAoaAzimuthLower()), 9, 7), 16), 186 (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat( 187 UwbUtil.radianTodegree( 188 params.getRangeDataNtfAoaAzimuthUpper()), 9, 7), 16), 189 (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat( 190 UwbUtil.radianTodegree( 191 params.getRangeDataNtfAoaElevationLower()), 9, 7), 16), 192 (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat( 193 UwbUtil.radianTodegree( 194 params.getRangeDataNtfAoaElevationUpper()), 9, 7), 16), 195 }); 196 } 197 if (params.isDiagnosticsEnabled()) { 198 tlvBufferBuilder.putByte(ConfigParam.ENABLE_DIAGNOSTICS_RSSI, (byte) 1); 199 if (SdkLevel.isAtLeastU()) { 200 // Fixed bug to be compliant with HAL interface. 201 tlvBufferBuilder.putByte(ConfigParam.ENABLE_DIAGRAMS_FRAME_REPORTS_FIELDS, 202 params.getDiagramsFrameReportsFieldsFlags()); 203 } else { 204 tlvBufferBuilder.putInt(ConfigParam.ENABLE_DIAGRAMS_FRAME_REPORTS_FIELDS, 205 params.getDiagramsFrameReportsFieldsFlags()); 206 } 207 } 208 if (params.getScheduledMode() == FiraParams.CONTENTION_BASED_RANGING) { 209 tlvBufferBuilder.putByteArray(ConfigParam.CAP_SIZE_RANGE, params.getCapSize()); 210 } 211 if (params.getDeviceRole() == FiraParams.RANGING_DEVICE_UT_TAG) { 212 tlvBufferBuilder.putInt(ConfigParam.UL_TDOA_TX_INTERVAL, 213 params.getUlTdoaTxIntervalMs()); 214 tlvBufferBuilder.putInt(ConfigParam.UL_TDOA_RANDOM_WINDOW, 215 params.getUlTdoaRandomWindowMs()); 216 tlvBufferBuilder.putByteArray(ConfigParam.UL_TDOA_DEVICE_ID, getUlTdoaDeviceId( 217 params.getUlTdoaDeviceIdType(), params.getUlTdoaDeviceId())); 218 tlvBufferBuilder.putByte(ConfigParam.UL_TDOA_TX_TIMESTAMP, 219 (byte) params.getUlTdoaTxTimestampType()); 220 } 221 if (params.getDeviceRole() == FiraParams.RANGING_DEVICE_ROLE_ADVERTISER || 222 params.getDeviceRole() == FiraParams.RANGING_DEVICE_ROLE_OBSERVER) { 223 tlvBufferBuilder 224 .putByte(ConfigParam.MIN_FRAMES_PER_RR, (byte) params.getMinFramesPerRr()) 225 .putShort(ConfigParam.MTU_SIZE, (short) params.getMtuSize()) 226 .putByte(ConfigParam.INTER_FRAME_INTERVAL, 227 (byte) params.getInterFrameInterval()); 228 } 229 return tlvBufferBuilder.build(); 230 } 231 getUlTdoaDeviceId(int ulTdoaDeviceIdType, byte[] ulTdoaDeviceId)232 private byte[] getUlTdoaDeviceId(int ulTdoaDeviceIdType, byte[] ulTdoaDeviceId) { 233 if (ulTdoaDeviceIdType == FiraParams.UL_TDOA_DEVICE_ID_NONE) { 234 // Device ID not included 235 return new byte[]{0}; 236 } 237 ByteBuffer buffer = ByteBuffer.allocate(ulTdoaDeviceId.length + 1); 238 buffer.put((byte) ulTdoaDeviceIdType); 239 buffer.put(ulTdoaDeviceId); 240 return buffer.array(); 241 } 242 getTlvBufferFromFiraRangingReconfigureParams(Params baseParam)243 private TlvBuffer getTlvBufferFromFiraRangingReconfigureParams(Params baseParam) { 244 FiraRangingReconfigureParams params = (FiraRangingReconfigureParams) baseParam; 245 TlvBuffer.Builder tlvBuilder = new TlvBuffer.Builder(); 246 Integer blockStrideLength = params.getBlockStrideLength(); 247 Integer rangeDataNtfConfig = params.getRangeDataNtfConfig(); 248 Integer rangeDataProximityNear = params.getRangeDataProximityNear(); 249 Integer rangeDataProximityFar = params.getRangeDataProximityFar(); 250 Double rangeDataAoaAzimuthLower = params.getRangeDataAoaAzimuthLower(); 251 Double rangeDataAoaAzimuthUpper = params.getRangeDataAoaAzimuthUpper(); 252 Double rangeDataAoaElevationLower = params.getRangeDataAoaElevationLower(); 253 Double rangeDataAoaElevationUpper = params.getRangeDataAoaElevationUpper(); 254 255 if (blockStrideLength != null) { 256 tlvBuilder.putByte(ConfigParam.BLOCK_STRIDE_LENGTH, 257 (byte) blockStrideLength.intValue()); 258 } 259 260 if (rangeDataNtfConfig != null) { 261 tlvBuilder.putByte(ConfigParam.RANGE_DATA_NTF_CONFIG, 262 (byte) rangeDataNtfConfig.intValue()); 263 } 264 265 if (rangeDataProximityNear != null) { 266 tlvBuilder.putShort(ConfigParam.RANGE_DATA_NTF_PROXIMITY_NEAR, 267 (short) rangeDataProximityNear.intValue()); 268 } 269 270 if (rangeDataProximityFar != null) { 271 tlvBuilder.putShort(ConfigParam.RANGE_DATA_NTF_PROXIMITY_FAR, 272 (short) rangeDataProximityFar.intValue()); 273 } 274 275 if (rangeDataNtfConfig != null && hasAoaBoundInRangeDataNtfConfig(rangeDataNtfConfig)) { 276 if ((rangeDataAoaAzimuthLower != null && rangeDataAoaAzimuthUpper != null) 277 || (rangeDataAoaElevationLower != null && rangeDataAoaElevationUpper != null)) { 278 rangeDataAoaAzimuthLower = rangeDataAoaAzimuthLower != null 279 ? rangeDataAoaAzimuthLower 280 : FiraParams.RANGE_DATA_NTF_AOA_AZIMUTH_LOWER_DEFAULT; 281 rangeDataAoaAzimuthUpper = rangeDataAoaAzimuthUpper != null 282 ? rangeDataAoaAzimuthUpper 283 : FiraParams.RANGE_DATA_NTF_AOA_AZIMUTH_UPPER_DEFAULT; 284 rangeDataAoaElevationLower = rangeDataAoaElevationLower != null 285 ? rangeDataAoaElevationLower 286 : FiraParams.RANGE_DATA_NTF_AOA_ELEVATION_LOWER_DEFAULT; 287 rangeDataAoaElevationUpper = rangeDataAoaElevationUpper != null 288 ? rangeDataAoaElevationUpper 289 : FiraParams.RANGE_DATA_NTF_AOA_ELEVATION_UPPER_DEFAULT; 290 tlvBuilder.putShortArray(ConfigParam.RANGE_DATA_NTF_AOA_BOUND, new short[]{ 291 // TODO (b/235355249): Verify this conversion. This is using AOA value 292 // in UwbTwoWayMeasurement to external RangingMeasurement conversion as 293 // reference. 294 (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat( 295 UwbUtil.radianTodegree( 296 rangeDataAoaAzimuthLower.floatValue()), 9, 7), 16), 297 (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat( 298 UwbUtil.radianTodegree( 299 rangeDataAoaAzimuthUpper.floatValue()), 9, 7), 16), 300 (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat( 301 UwbUtil.radianTodegree( 302 rangeDataAoaElevationLower.floatValue()), 9, 7), 16), 303 (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat( 304 UwbUtil.radianTodegree( 305 rangeDataAoaElevationUpper.floatValue()), 9, 7), 16), 306 }); 307 } 308 } 309 return tlvBuilder.build(); 310 } 311 312 // Merged data from other parameter values getResultReportConfig(FiraOpenSessionParams params)313 private int getResultReportConfig(FiraOpenSessionParams params) { 314 int resultReportConfig = 0x00; 315 resultReportConfig |= params.hasTimeOfFlightReport() ? 0x01 : 0x00; 316 resultReportConfig |= params.hasAngleOfArrivalAzimuthReport() ? 0x02 : 0x00; 317 resultReportConfig |= params.hasAngleOfArrivalElevationReport() ? 0x04 : 0x00; 318 resultReportConfig |= params.hasAngleOfArrivalFigureOfMeritReport() ? 0x08 : 0x00; 319 return resultReportConfig; 320 } 321 getRangingRoundControl(FiraOpenSessionParams params)322 private int getRangingRoundControl(FiraOpenSessionParams params) { 323 // RANGING_ROUND_CONTROL 324 byte rangingRoundControl = 0x00; 325 326 // b0 : Ranging Result Report Message 327 rangingRoundControl |= (byte) (params.hasRangingResultReportMessage() ? 0x01 : 0x00); 328 329 // b1 : Control Message 330 rangingRoundControl |= (byte) (params.hasControlMessage() ? 0x02 : 0x00); 331 332 // b2 : Ranging Control Phase 333 rangingRoundControl |= (byte) (params.hasRangingControlPhase() ? 0x04 : 0x00); 334 335 // b7 : Measurement Report Message 336 if (params.getMeasurementReportType() 337 == FiraParams.MEASUREMENT_REPORT_TYPE_RESPONDER_TO_INITIATOR) { 338 rangingRoundControl |= 0x80; 339 } 340 341 return rangingRoundControl; 342 } 343 getComputedMacAddress(UwbAddress address)344 private static byte[] getComputedMacAddress(UwbAddress address) { 345 if (!SdkLevel.isAtLeastU()) { 346 return TlvUtil.getReverseBytes(address.toBytes()); 347 } 348 return address.toBytes(); 349 } 350 getComputedVendorId(byte[] data)351 private static byte[] getComputedVendorId(byte[] data) { 352 if (!SdkLevel.isAtLeastU()) { 353 return TlvUtil.getReverseBytes(data); 354 } 355 return data; 356 } 357 } 358