• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.UwbInjector;
28 import com.android.server.uwb.config.ConfigParam;
29 import com.android.server.uwb.util.UwbUtil;
30 
31 import com.google.uwb.support.base.Params;
32 import com.google.uwb.support.base.ProtocolVersion;
33 import com.google.uwb.support.fira.FiraOpenSessionParams;
34 import com.google.uwb.support.fira.FiraParams;
35 import com.google.uwb.support.fira.FiraProtocolVersion;
36 import com.google.uwb.support.fira.FiraRangingReconfigureParams;
37 
38 import java.nio.ByteBuffer;
39 import java.util.Arrays;
40 
41 public class FiraEncoder extends TlvEncoder {
42     private final UwbInjector mUwbInjector;
43 
FiraEncoder(UwbInjector uwbInjector)44     public FiraEncoder(UwbInjector uwbInjector) {
45         mUwbInjector = uwbInjector;
46     }
47 
48     @Override
getTlvBuffer(Params param, ProtocolVersion protocolVersion)49     public TlvBuffer getTlvBuffer(Params param, ProtocolVersion protocolVersion) {
50         // The "protocolVersion" is always expected to be of type "FiraProtocolVersion" here, but
51         // in case it's not, we use a backup value of "PROTOCOL_VERSION_1_1".
52         FiraProtocolVersion uwbsFiraProtocolVersion =
53                 (protocolVersion instanceof FiraProtocolVersion)
54                         ? (FiraProtocolVersion) protocolVersion : FiraParams.PROTOCOL_VERSION_1_1;
55         if (param instanceof FiraOpenSessionParams) {
56             return getTlvBufferFromFiraOpenSessionParams(param, uwbsFiraProtocolVersion);
57         }
58 
59         if (param instanceof FiraRangingReconfigureParams) {
60             return getTlvBufferFromFiraRangingReconfigureParams(param);
61         }
62         return null;
63     }
64 
hasAoaBoundInRangeDataNtfConfig(int rangeDataNtfConfig)65     private static boolean hasAoaBoundInRangeDataNtfConfig(int rangeDataNtfConfig) {
66         return rangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_AOA_LEVEL_TRIG
67                 || rangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_LEVEL_TRIG
68                 || rangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_AOA_EDGE_TRIG
69                 || rangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_EDGE_TRIG;
70     }
71 
getTlvBufferFromFiraOpenSessionParams( Params baseParam, FiraProtocolVersion uwbsFiraProtocolVersion)72     private TlvBuffer getTlvBufferFromFiraOpenSessionParams(
73             Params baseParam, FiraProtocolVersion uwbsFiraProtocolVersion) {
74         FiraOpenSessionParams params = (FiraOpenSessionParams) baseParam;
75         int deviceType = params.getDeviceType();
76         int resultReportConfig = getResultReportConfig(params);
77         int rangingRoundControl = getRangingRoundControl(params);
78         int deviceRole = params.getDeviceRole();
79 
80         TlvBuffer.Builder tlvBufferBuilder = new TlvBuffer.Builder()
81                 .putByte(ConfigParam.RANGING_ROUND_USAGE, (byte) params.getRangingRoundUsage())
82                 .putByte(ConfigParam.STS_CONFIG, (byte) params.getStsConfig())
83                 .putByte(ConfigParam.MULTI_NODE_MODE, (byte) params.getMultiNodeMode())
84                 .putByte(ConfigParam.CHANNEL_NUMBER, (byte) params.getChannelNumber())
85                 .putByteArray(ConfigParam.DEVICE_MAC_ADDRESS, params.getDeviceAddress().size(),
86                         getComputedMacAddress(params.getDeviceAddress()))
87                 .putShort(ConfigParam.SLOT_DURATION, (short) params.getSlotDurationRstu())
88                 .putByte(ConfigParam.MAC_FCS_TYPE, (byte) params.getFcsType())
89                 .putByte(ConfigParam.RANGING_ROUND_CONTROL,
90                         (byte) rangingRoundControl/* params.getMeasurementReportType()*/)
91                 .putByte(ConfigParam.AOA_RESULT_REQ, (byte) params.getAoaResultRequest())
92                 .putByte(ConfigParam.RANGE_DATA_NTF_CONFIG, (byte) params.getRangeDataNtfConfig())
93                 .putShort(ConfigParam.RANGE_DATA_NTF_PROXIMITY_NEAR,
94                         (short) params.getRangeDataNtfProximityNear())
95                 .putShort(ConfigParam.RANGE_DATA_NTF_PROXIMITY_FAR,
96                         (short) params.getRangeDataNtfProximityFar())
97                 .putByte(ConfigParam.DEVICE_ROLE, (byte) params.getDeviceRole())
98                 .putByte(ConfigParam.RFRAME_CONFIG, (byte) params.getRframeConfig())
99                 .putByte(ConfigParam.RSSI_REPORTING,
100                         (byte) (params.isRssiReportingEnabled() ? 1 : 0))
101                 .putByte(ConfigParam.PREAMBLE_CODE_INDEX, (byte) params.getPreambleCodeIndex())
102                 .putByte(ConfigParam.SFD_ID, (byte) params.getSfdId())
103                 .putByte(ConfigParam.PSDU_DATA_RATE, (byte) params.getPsduDataRate())
104                 .putByte(ConfigParam.PREAMBLE_DURATION, (byte) params.getPreambleDuration())
105                 // n.a. for OWR UL-TDoA and 0x01 for all other RangingRoundUsage values.
106                 .putByte(ConfigParam.RANGING_TIME_STRUCT, (byte) params.getRangingTimeStruct())
107                 .putByte(ConfigParam.SLOTS_PER_RR, (byte) params.getSlotsPerRangingRound())
108                 .putByte(ConfigParam.PRF_MODE, (byte) params.getPrfMode())
109                 .putByte(ConfigParam.SCHEDULED_MODE, (byte) params.getScheduledMode())
110                 .putByte(ConfigParam.KEY_ROTATION,
111                         params.isKeyRotationEnabled() ? (byte) 1 : (byte) 0)
112                 .putByte(ConfigParam.KEY_ROTATION_RATE, (byte) params.getKeyRotationRate())
113                 .putByte(ConfigParam.SESSION_PRIORITY, (byte) params.getSessionPriority())
114                 .putByte(ConfigParam.MAC_ADDRESS_MODE, (byte) params.getMacAddressMode())
115                 .putByte(ConfigParam.NUMBER_OF_STS_SEGMENTS, (byte) params.getStsSegmentCount())
116                 .putShort(ConfigParam.MAX_RR_RETRY, (short) params.getMaxRangingRoundRetries())
117                 .putByte(ConfigParam.HOPPING_MODE,
118                         (byte) params.getHoppingMode())
119                 .putByte(ConfigParam.BLOCK_STRIDE_LENGTH, (byte) params.getBlockStrideLength())
120                 .putByte(ConfigParam.RESULT_REPORT_CONFIG, (byte) resultReportConfig)
121                 .putByte(ConfigParam.IN_BAND_TERMINATION_ATTEMPT_COUNT,
122                         (byte) params.getInBandTerminationAttemptCount())
123                 .putShort(ConfigParam.MAX_NUMBER_OF_MEASUREMENTS,
124                         (short) params.getMaxNumberOfMeasurements())
125                 .putByte(ConfigParam.STS_LENGTH, (byte) params.getStsLength());
126         if (params.getPrfMode() == FiraParams.PRF_MODE_BPRF) {
127             tlvBufferBuilder.putByte(
128                 ConfigParam.BPRF_PHR_DATA_RATE, (byte) params.getBprfPhrDataRate());
129         }
130         if (params.getDeviceRole() != FiraParams.RANGING_DEVICE_UT_TAG) {
131             tlvBufferBuilder.putInt(ConfigParam.RANGING_INTERVAL, params.getRangingIntervalMs());
132         }
133         if (deviceRole != FiraParams.RANGING_DEVICE_DT_TAG) {
134             tlvBufferBuilder.putByte(ConfigParam.DEVICE_TYPE, (byte) params.getDeviceType());
135         }
136 
137         if (isTimeScheduledTwrSession(
138                     params.getScheduledMode(), params.getRangingRoundUsage()))  {
139             if (params.getDestAddressList().size() > 0) {
140                 ByteBuffer dstAddressList = ByteBuffer.allocate(1024);
141                 for (UwbAddress address : params.getDestAddressList()) {
142                     dstAddressList.put(getComputedMacAddress(address));
143                 }
144                 tlvBufferBuilder
145                         .putByte(ConfigParam.NUMBER_OF_CONTROLEES,
146                                 (byte) params.getDestAddressList().size())
147                         .putByteArray(
148                                 ConfigParam.DST_MAC_ADDRESS, dstAddressList.position(),
149                                 Arrays.copyOf(dstAddressList.array(), dstAddressList.position()));
150             }
151         }
152 
153         if (uwbsFiraProtocolVersion.getMajor() >= 2) {
154             // Initiation time Changed from 4 byte field to 8 byte field in version 2.
155             if (deviceRole != FiraParams.RANGING_DEVICE_DT_TAG) {
156                 // For FiRa 2.0+ device, prefer to set the Absolute UWB Initiation time.
157                 if (params.getAbsoluteInitiationTime() > 0) {
158                     tlvBufferBuilder.putLong(ConfigParam.UWB_INITIATION_TIME,
159                             params.getAbsoluteInitiationTime());
160                 } else {
161                     tlvBufferBuilder.putLong(ConfigParam.UWB_INITIATION_TIME,
162                             params.getInitiationTime());
163                 }
164             } else {
165                 tlvBufferBuilder.putByte(ConfigParam.DL_TDOA_BLOCK_STRIDING,
166                     (byte) params.getDlTdoaBlockStriding());
167             }
168             tlvBufferBuilder.putByte(ConfigParam.LINK_LAYER_MODE, (byte) params.getLinkLayerMode())
169                     .putByte(ConfigParam.DATA_REPETITION_COUNT,
170                             (byte) params.getDataRepetitionCount())
171                     .putByte(ConfigParam.SESSION_DATA_TRANSFER_STATUS_NTF_CONFIG,
172                             params.getSessionDataTransferStatusNtfConfig() ? (byte) 1 : (byte) 0)
173                     .putByte(ConfigParam.APPLICATION_DATA_ENDPOINT,
174                             (byte) params.getApplicationDataEndpoint());
175             if (deviceType == FiraParams.RANGING_DEVICE_TYPE_CONTROLLER && UwbUtil.isBitSet(
176                              params.getReferenceTimeBase(),
177                              FiraParams.SESSION_TIME_BASE_REFERENCE_FEATURE_ENABLED)) {
178                 tlvBufferBuilder.putByteArray(ConfigParam.SESSION_TIME_BASE,
179                             getSessionTimeBase(params));
180             }
181         } else {
182             if (deviceRole != FiraParams.RANGING_DEVICE_DT_TAG) {
183                 tlvBufferBuilder
184                         .putInt(ConfigParam.UWB_INITIATION_TIME,
185                                 Math.toIntExact(params.getInitiationTime()));
186             }
187             tlvBufferBuilder.putByte(ConfigParam.TX_ADAPTIVE_PAYLOAD_POWER,
188                         params.isTxAdaptivePayloadPowerEnabled() ? (byte) 1 : (byte) 0);
189         }
190 
191         configureStsParameters(tlvBufferBuilder, params);
192 
193         if (params.getAoaResultRequest()
194                 == FiraParams.AOA_RESULT_REQUEST_MODE_REQ_AOA_RESULTS_INTERLEAVED) {
195             tlvBufferBuilder.putByte(ConfigParam.NUM_RANGE_MEASUREMENTS,
196                             (byte) params.getNumOfMsrmtFocusOnRange())
197                     .putByte(ConfigParam.NUM_AOA_AZIMUTH_MEASUREMENTS,
198                             (byte) params.getNumOfMsrmtFocusOnAoaAzimuth())
199                     .putByte(ConfigParam.NUM_AOA_ELEVATION_MEASUREMENTS,
200                             (byte) params.getNumOfMsrmtFocusOnAoaElevation());
201         }
202         if (hasAoaBoundInRangeDataNtfConfig(params.getRangeDataNtfConfig())) {
203             tlvBufferBuilder.putShortArray(ConfigParam.RANGE_DATA_NTF_AOA_BOUND, new short[]{
204                     // TODO (b/235355249): Verify this conversion. This is using AOA value
205                     // in UwbTwoWayMeasurement to external RangingMeasurement conversion as
206                     // reference.
207                     (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
208                             UwbUtil.radianTodegree(
209                                     params.getRangeDataNtfAoaAzimuthLower()), 9, 7), 16),
210                     (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
211                             UwbUtil.radianTodegree(
212                                     params.getRangeDataNtfAoaAzimuthUpper()), 9, 7), 16),
213                     (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
214                             UwbUtil.radianTodegree(
215                                     params.getRangeDataNtfAoaElevationLower()), 9, 7), 16),
216                     (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
217                             UwbUtil.radianTodegree(
218                                     params.getRangeDataNtfAoaElevationUpper()), 9, 7), 16),
219             });
220         }
221         if (params.isDiagnosticsEnabled()) {
222             tlvBufferBuilder.putByte(ConfigParam.ENABLE_DIAGNOSTICS_RSSI, (byte) 1);
223             if (SdkLevel.isAtLeastU()) {
224                 // Fixed bug to be compliant with HAL interface.
225                 tlvBufferBuilder.putByte(ConfigParam.ENABLE_DIAGRAMS_FRAME_REPORTS_FIELDS,
226                         params.getDiagramsFrameReportsFieldsFlags());
227             } else {
228                 tlvBufferBuilder.putInt(ConfigParam.ENABLE_DIAGRAMS_FRAME_REPORTS_FIELDS,
229                         params.getDiagramsFrameReportsFieldsFlags());
230             }
231         }
232         if (params.getScheduledMode() == FiraParams.CONTENTION_BASED_RANGING) {
233             tlvBufferBuilder.putByteArray(ConfigParam.CAP_SIZE_RANGE, params.getCapSize());
234         }
235         if (params.getDeviceRole() == FiraParams.RANGING_DEVICE_UT_TAG) {
236             tlvBufferBuilder.putInt(ConfigParam.UL_TDOA_TX_INTERVAL,
237                     params.getUlTdoaTxIntervalMs());
238             tlvBufferBuilder.putInt(ConfigParam.UL_TDOA_RANDOM_WINDOW,
239                     params.getUlTdoaRandomWindowMs());
240             tlvBufferBuilder.putByteArray(ConfigParam.UL_TDOA_DEVICE_ID, getUlTdoaDeviceId(
241                     params.getUlTdoaDeviceIdType(), params.getUlTdoaDeviceId()));
242             tlvBufferBuilder.putByte(ConfigParam.UL_TDOA_TX_TIMESTAMP,
243                     (byte) params.getUlTdoaTxTimestampType());
244         }
245         if (params.getDeviceRole() == FiraParams.RANGING_DEVICE_ROLE_ADVERTISER ||
246                 params.getDeviceRole() == FiraParams.RANGING_DEVICE_ROLE_OBSERVER) {
247             tlvBufferBuilder
248                     .putByte(ConfigParam.MIN_FRAMES_PER_RR, (byte) params.getMinFramesPerRr())
249                     .putShort(ConfigParam.MTU_SIZE, (short) params.getMtuSize())
250                     .putByte(ConfigParam.INTER_FRAME_INTERVAL,
251                             (byte) params.getInterFrameInterval());
252         }
253 
254         if (mUwbInjector.getDeviceConfigFacade().isAntennaModeConfigSupported()) {
255             tlvBufferBuilder.putByte(ConfigParam.ANTENNA_MODE, params.getAntennaMode());
256         }
257         return tlvBufferBuilder.build();
258     }
259 
isTimeScheduledTwrSession(int scheduledMode, int rangingUsage)260     private boolean isTimeScheduledTwrSession(int scheduledMode, int rangingUsage) {
261         if (scheduledMode == FiraParams.TIME_SCHEDULED_RANGING) {
262             if (rangingUsage == FiraParams.RANGING_ROUND_USAGE_SS_TWR_DEFERRED_MODE
263                     || rangingUsage == FiraParams.RANGING_ROUND_USAGE_DS_TWR_DEFERRED_MODE
264                     || rangingUsage == FiraParams.RANGING_ROUND_USAGE_SS_TWR_NON_DEFERRED_MODE
265                     || rangingUsage == FiraParams.RANGING_ROUND_USAGE_DS_TWR_NON_DEFERRED_MODE) {
266                 return true;
267             }
268         }
269         return false;
270     }
271 
configureStsParameters(TlvBuffer.Builder tlvBufferBuilder, FiraOpenSessionParams params)272     private void configureStsParameters(TlvBuffer.Builder tlvBufferBuilder,
273         FiraOpenSessionParams params) {
274         int stsConfig = params.getStsConfig();
275 
276         if (stsConfig == FiraParams.STS_CONFIG_STATIC) {
277              tlvBufferBuilder
278                     .putByteArray(ConfigParam.VENDOR_ID, params.getVendorId() != null
279                             ? getComputedVendorId(params.getVendorId()): null)
280                     .putByteArray(ConfigParam.STATIC_STS_IV, params.getStaticStsIV());
281         } else if (stsConfig == FiraParams.STS_CONFIG_DYNAMIC_FOR_CONTROLEE_INDIVIDUAL_KEY) {
282             if (params.getDeviceType() == FiraParams.RANGING_DEVICE_TYPE_CONTROLEE) {
283                 tlvBufferBuilder.putInt(ConfigParam.SUB_SESSION_ID, params.getSubSessionId());
284             }
285         } else if (stsConfig == FiraParams.STS_CONFIG_PROVISIONED) {
286             if (params.getSessionKey() != null ) {
287                 tlvBufferBuilder.putByteArray(ConfigParam.SESSION_KEY, params.getSessionKey());
288             }
289         } else if (stsConfig == FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY) {
290             if (params.getDeviceType() == FiraParams.RANGING_DEVICE_TYPE_CONTROLEE) {
291                 tlvBufferBuilder.putInt(ConfigParam.SUB_SESSION_ID, params.getSubSessionId());
292                 if (params.getSubsessionKey() != null ) {
293                     tlvBufferBuilder.
294                           putByteArray(ConfigParam.SUBSESSION_KEY, params.getSubsessionKey());
295                 }
296             }
297             if (params.getSessionKey() != null ) {
298                 tlvBufferBuilder.putByteArray(ConfigParam.SESSION_KEY, params.getSessionKey());
299             }
300         }
301     }
302 
getUlTdoaDeviceId(int ulTdoaDeviceIdType, byte[] ulTdoaDeviceId)303     private byte[] getUlTdoaDeviceId(int ulTdoaDeviceIdType, byte[] ulTdoaDeviceId) {
304         if (ulTdoaDeviceIdType == FiraParams.UL_TDOA_DEVICE_ID_NONE) {
305             // Device ID not included
306             return new byte[]{0};
307         }
308         ByteBuffer buffer = ByteBuffer.allocate(ulTdoaDeviceId.length + 1);
309         buffer.put((byte) ulTdoaDeviceIdType);
310         buffer.put(ulTdoaDeviceId);
311         return buffer.array();
312     }
313 
getTlvBufferFromFiraRangingReconfigureParams(Params baseParam)314     private TlvBuffer getTlvBufferFromFiraRangingReconfigureParams(Params baseParam) {
315         FiraRangingReconfigureParams params = (FiraRangingReconfigureParams) baseParam;
316         TlvBuffer.Builder tlvBuilder = new TlvBuffer.Builder();
317         Integer blockStrideLength = params.getBlockStrideLength();
318         Integer rangeDataNtfConfig = params.getRangeDataNtfConfig();
319         Integer rangeDataProximityNear = params.getRangeDataProximityNear();
320         Integer rangeDataProximityFar = params.getRangeDataProximityFar();
321         Double rangeDataAoaAzimuthLower = params.getRangeDataAoaAzimuthLower();
322         Double rangeDataAoaAzimuthUpper = params.getRangeDataAoaAzimuthUpper();
323         Double rangeDataAoaElevationLower = params.getRangeDataAoaElevationLower();
324         Double rangeDataAoaElevationUpper = params.getRangeDataAoaElevationUpper();
325         Integer suspendRangingRounds = params.getSuspendRangingRounds();
326 
327         if (blockStrideLength != null) {
328             tlvBuilder.putByte(ConfigParam.BLOCK_STRIDE_LENGTH,
329                     (byte) blockStrideLength.intValue());
330         }
331 
332         if (rangeDataNtfConfig != null) {
333             tlvBuilder.putByte(ConfigParam.RANGE_DATA_NTF_CONFIG,
334                     (byte) rangeDataNtfConfig.intValue());
335         }
336 
337         if (rangeDataProximityNear != null) {
338             tlvBuilder.putShort(ConfigParam.RANGE_DATA_NTF_PROXIMITY_NEAR,
339                     (short) rangeDataProximityNear.intValue());
340         }
341 
342         if (rangeDataProximityFar != null) {
343             tlvBuilder.putShort(ConfigParam.RANGE_DATA_NTF_PROXIMITY_FAR,
344                     (short) rangeDataProximityFar.intValue());
345         }
346 
347         if (rangeDataNtfConfig != null && hasAoaBoundInRangeDataNtfConfig(rangeDataNtfConfig)) {
348             if ((rangeDataAoaAzimuthLower != null && rangeDataAoaAzimuthUpper != null)
349                     || (rangeDataAoaElevationLower != null && rangeDataAoaElevationUpper != null)) {
350                 rangeDataAoaAzimuthLower = rangeDataAoaAzimuthLower != null
351                         ? rangeDataAoaAzimuthLower
352                         : FiraParams.RANGE_DATA_NTF_AOA_AZIMUTH_LOWER_DEFAULT;
353                 rangeDataAoaAzimuthUpper = rangeDataAoaAzimuthUpper != null
354                         ? rangeDataAoaAzimuthUpper
355                         : FiraParams.RANGE_DATA_NTF_AOA_AZIMUTH_UPPER_DEFAULT;
356                 rangeDataAoaElevationLower = rangeDataAoaElevationLower != null
357                         ? rangeDataAoaElevationLower
358                         : FiraParams.RANGE_DATA_NTF_AOA_ELEVATION_LOWER_DEFAULT;
359                 rangeDataAoaElevationUpper = rangeDataAoaElevationUpper != null
360                         ? rangeDataAoaElevationUpper
361                         : FiraParams.RANGE_DATA_NTF_AOA_ELEVATION_UPPER_DEFAULT;
362                 tlvBuilder.putShortArray(ConfigParam.RANGE_DATA_NTF_AOA_BOUND, new short[]{
363                         // TODO (b/235355249): Verify this conversion. This is using AOA value
364                         // in UwbTwoWayMeasurement to external RangingMeasurement conversion as
365                         // reference.
366                         (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
367                                 UwbUtil.radianTodegree(
368                                         rangeDataAoaAzimuthLower.floatValue()), 9, 7), 16),
369                         (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
370                                 UwbUtil.radianTodegree(
371                                         rangeDataAoaAzimuthUpper.floatValue()), 9, 7), 16),
372                         (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
373                                 UwbUtil.radianTodegree(
374                                         rangeDataAoaElevationLower.floatValue()), 9, 7), 16),
375                         (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
376                                 UwbUtil.radianTodegree(
377                                         rangeDataAoaElevationUpper.floatValue()), 9, 7), 16),
378                 });
379             }
380         }
381         if (suspendRangingRounds != null) {
382                 tlvBuilder.putByte(ConfigParam.SUSPEND_RANGING_ROUNDS,
383                         (byte) suspendRangingRounds.intValue());
384         }
385         return tlvBuilder.build();
386     }
387 
388     // Merged data from other parameter values
getResultReportConfig(FiraOpenSessionParams params)389     private int getResultReportConfig(FiraOpenSessionParams params) {
390         int resultReportConfig = 0x00;
391         resultReportConfig |= params.hasTimeOfFlightReport() ? 0x01 : 0x00;
392         resultReportConfig |= params.hasAngleOfArrivalAzimuthReport() ? 0x02 : 0x00;
393         resultReportConfig |= params.hasAngleOfArrivalElevationReport() ? 0x04 : 0x00;
394         resultReportConfig |= params.hasAngleOfArrivalFigureOfMeritReport() ? 0x08 : 0x00;
395         return resultReportConfig;
396     }
397 
getRangingRoundControl(FiraOpenSessionParams params)398     private int getRangingRoundControl(FiraOpenSessionParams params) {
399         // RANGING_ROUND_CONTROL
400         byte rangingRoundControl = 0x00;
401 
402         // b0 : Ranging Result Report Message
403         rangingRoundControl |= (byte) (params.hasRangingResultReportMessage() ? 0x01 : 0x00);
404 
405         // b1 : Control Message
406         rangingRoundControl |= (byte) (params.hasControlMessage() ? 0x02 : 0x00);
407 
408         // b2 : Ranging Control Phase
409         rangingRoundControl |= (byte) (params.hasRangingControlPhase() ? 0x04 : 0x00);
410 
411         // b6 : Measurement Report Message
412         if (params.getScheduledMode() == FiraParams.CONTENTION_BASED_RANGING) {
413             if (params.getMeasurementReportPhase() == FiraParams.MEASUREMENT_REPORT_PHASE_SET) {
414                 rangingRoundControl |= (byte) 0x40;
415             }
416         }
417 
418         // b7 : Measurement Report Message
419         if (params.getMeasurementReportType()
420                 == FiraParams.MEASUREMENT_REPORT_TYPE_RESPONDER_TO_INITIATOR) {
421             rangingRoundControl |= (byte) 0x80;
422         }
423         return rangingRoundControl;
424     }
425 
getComputedMacAddress(UwbAddress address)426     private static byte[] getComputedMacAddress(UwbAddress address) {
427         if (!SdkLevel.isAtLeastU()) {
428             return TlvUtil.getReverseBytes(address.toBytes());
429         }
430         return address.toBytes();
431     }
432 
getComputedVendorId(byte[] data)433     private static byte[] getComputedVendorId(byte[] data) {
434         if (!SdkLevel.isAtLeastU()) {
435             return TlvUtil.getReverseBytes(data);
436         }
437         return data;
438     }
439 
getSessionTimeBase(FiraOpenSessionParams params)440     private byte[] getSessionTimeBase(FiraOpenSessionParams params) {
441         byte[] sessionTimeBaseParam = new byte[FiraParams.SESSION_TIME_BASE_PARAM_LEN];
442         int offset = 0;
443         sessionTimeBaseParam[offset++] = (byte) params.getReferenceTimeBase();
444         byte[] sessionHandleValue = TlvUtil.getBytes(params.getReferenceSessionHandle());
445         for (int index = FiraParams.SESSION_HANDLE_LEN - 1; index >= 0; index--) {
446             sessionTimeBaseParam[offset++] = (byte) sessionHandleValue[index];
447         }
448         byte[] sessionOffsetInMicroSecondValue =
449                 TlvUtil.getBytes(params.getSessionOffsetInMicroSeconds());
450         for (int index = FiraParams.SESSION_OFFSET_TIME_LEN - 1; index >= 0; index--) {
451             sessionTimeBaseParam[offset++] = (byte) sessionOffsetInMicroSecondValue[index];
452         }
453         return sessionTimeBaseParam;
454     }
455 }
456