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                 .putByte(ConfigParam.BPRF_PHR_DATA_RATE,
124                         (byte) params.getBprfPhrDataRate())
125                 .putShort(ConfigParam.MAX_NUMBER_OF_MEASUREMENTS,
126                         (short) params.getMaxNumberOfMeasurements())
127                 .putByte(ConfigParam.STS_LENGTH, (byte) params.getStsLength());
128         if (params.getDeviceRole() != FiraParams.RANGING_DEVICE_UT_TAG) {
129             tlvBufferBuilder.putInt(ConfigParam.RANGING_INTERVAL, params.getRangingIntervalMs());
130         }
131         if (deviceRole != FiraParams.RANGING_DEVICE_DT_TAG) {
132             tlvBufferBuilder.putByte(ConfigParam.DEVICE_TYPE, (byte) params.getDeviceType());
133         }
134 
135         if (isTimeScheduledTwrSession(
136                     params.getScheduledMode(), params.getRangingRoundUsage()))  {
137             if (params.getDestAddressList().size() > 0) {
138                 ByteBuffer dstAddressList = ByteBuffer.allocate(1024);
139                 for (UwbAddress address : params.getDestAddressList()) {
140                     dstAddressList.put(getComputedMacAddress(address));
141                 }
142                 tlvBufferBuilder
143                         .putByte(ConfigParam.NUMBER_OF_CONTROLEES,
144                                 (byte) params.getDestAddressList().size())
145                         .putByteArray(
146                                 ConfigParam.DST_MAC_ADDRESS, dstAddressList.position(),
147                                 Arrays.copyOf(dstAddressList.array(), dstAddressList.position()));
148             }
149         }
150 
151         if (uwbsFiraProtocolVersion.getMajor() >= 2) {
152             // Initiation time Changed from 4 byte field to 8 byte field in version 2.
153             if (deviceRole != FiraParams.RANGING_DEVICE_DT_TAG) {
154                 // For FiRa 2.0+ device, prefer to set the Absolute UWB Initiation time.
155                 if (params.getAbsoluteInitiationTime() > 0) {
156                     tlvBufferBuilder.putLong(ConfigParam.UWB_INITIATION_TIME,
157                             params.getAbsoluteInitiationTime());
158                 } else {
159                     tlvBufferBuilder.putLong(ConfigParam.UWB_INITIATION_TIME,
160                             params.getInitiationTime());
161                 }
162             } else {
163                 tlvBufferBuilder.putByte(ConfigParam.DL_TDOA_BLOCK_STRIDING,
164                     (byte) params.getDlTdoaBlockStriding());
165             }
166             tlvBufferBuilder.putByte(ConfigParam.LINK_LAYER_MODE, (byte) params.getLinkLayerMode())
167                     .putByte(ConfigParam.DATA_REPETITION_COUNT,
168                             (byte) params.getDataRepetitionCount())
169                     .putByte(ConfigParam.SESSION_DATA_TRANSFER_STATUS_NTF_CONFIG,
170                             params.getSessionDataTransferStatusNtfConfig() ? (byte) 1 : (byte) 0)
171                     .putByte(ConfigParam.APPLICATION_DATA_ENDPOINT,
172                             (byte) params.getApplicationDataEndpoint());
173             if (deviceType == FiraParams.RANGING_DEVICE_TYPE_CONTROLLER && UwbUtil.isBitSet(
174                              params.getReferenceTimeBase(),
175                              FiraParams.SESSION_TIME_BASE_REFERENCE_FEATURE_ENABLED)) {
176                 tlvBufferBuilder.putByteArray(ConfigParam.SESSION_TIME_BASE,
177                             getSessionTimeBase(params));
178             }
179         } else {
180             if (deviceRole != FiraParams.RANGING_DEVICE_DT_TAG) {
181                 tlvBufferBuilder
182                         .putInt(ConfigParam.UWB_INITIATION_TIME,
183                                 Math.toIntExact(params.getInitiationTime()));
184             }
185             tlvBufferBuilder.putByte(ConfigParam.TX_ADAPTIVE_PAYLOAD_POWER,
186                         params.isTxAdaptivePayloadPowerEnabled() ? (byte) 1 : (byte) 0);
187         }
188 
189         configureStsParameters(tlvBufferBuilder, params);
190 
191         if (params.getAoaResultRequest()
192                 == FiraParams.AOA_RESULT_REQUEST_MODE_REQ_AOA_RESULTS_INTERLEAVED) {
193             tlvBufferBuilder.putByte(ConfigParam.NUM_RANGE_MEASUREMENTS,
194                             (byte) params.getNumOfMsrmtFocusOnRange())
195                     .putByte(ConfigParam.NUM_AOA_AZIMUTH_MEASUREMENTS,
196                             (byte) params.getNumOfMsrmtFocusOnAoaAzimuth())
197                     .putByte(ConfigParam.NUM_AOA_ELEVATION_MEASUREMENTS,
198                             (byte) params.getNumOfMsrmtFocusOnAoaElevation());
199         }
200         if (hasAoaBoundInRangeDataNtfConfig(params.getRangeDataNtfConfig())) {
201             tlvBufferBuilder.putShortArray(ConfigParam.RANGE_DATA_NTF_AOA_BOUND, new short[]{
202                     // TODO (b/235355249): Verify this conversion. This is using AOA value
203                     // in UwbTwoWayMeasurement to external RangingMeasurement conversion as
204                     // reference.
205                     (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
206                             UwbUtil.radianTodegree(
207                                     params.getRangeDataNtfAoaAzimuthLower()), 9, 7), 16),
208                     (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
209                             UwbUtil.radianTodegree(
210                                     params.getRangeDataNtfAoaAzimuthUpper()), 9, 7), 16),
211                     (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
212                             UwbUtil.radianTodegree(
213                                     params.getRangeDataNtfAoaElevationLower()), 9, 7), 16),
214                     (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
215                             UwbUtil.radianTodegree(
216                                     params.getRangeDataNtfAoaElevationUpper()), 9, 7), 16),
217             });
218         }
219         if (params.isDiagnosticsEnabled()) {
220             tlvBufferBuilder.putByte(ConfigParam.ENABLE_DIAGNOSTICS_RSSI, (byte) 1);
221             if (SdkLevel.isAtLeastU()) {
222                 // Fixed bug to be compliant with HAL interface.
223                 tlvBufferBuilder.putByte(ConfigParam.ENABLE_DIAGRAMS_FRAME_REPORTS_FIELDS,
224                         params.getDiagramsFrameReportsFieldsFlags());
225             } else {
226                 tlvBufferBuilder.putInt(ConfigParam.ENABLE_DIAGRAMS_FRAME_REPORTS_FIELDS,
227                         params.getDiagramsFrameReportsFieldsFlags());
228             }
229         }
230         if (params.getScheduledMode() == FiraParams.CONTENTION_BASED_RANGING) {
231             tlvBufferBuilder.putByteArray(ConfigParam.CAP_SIZE_RANGE, params.getCapSize());
232         }
233         if (params.getDeviceRole() == FiraParams.RANGING_DEVICE_UT_TAG) {
234             tlvBufferBuilder.putInt(ConfigParam.UL_TDOA_TX_INTERVAL,
235                     params.getUlTdoaTxIntervalMs());
236             tlvBufferBuilder.putInt(ConfigParam.UL_TDOA_RANDOM_WINDOW,
237                     params.getUlTdoaRandomWindowMs());
238             tlvBufferBuilder.putByteArray(ConfigParam.UL_TDOA_DEVICE_ID, getUlTdoaDeviceId(
239                     params.getUlTdoaDeviceIdType(), params.getUlTdoaDeviceId()));
240             tlvBufferBuilder.putByte(ConfigParam.UL_TDOA_TX_TIMESTAMP,
241                     (byte) params.getUlTdoaTxTimestampType());
242         }
243         if (params.getDeviceRole() == FiraParams.RANGING_DEVICE_ROLE_ADVERTISER ||
244                 params.getDeviceRole() == FiraParams.RANGING_DEVICE_ROLE_OBSERVER) {
245             tlvBufferBuilder
246                     .putByte(ConfigParam.MIN_FRAMES_PER_RR, (byte) params.getMinFramesPerRr())
247                     .putShort(ConfigParam.MTU_SIZE, (short) params.getMtuSize())
248                     .putByte(ConfigParam.INTER_FRAME_INTERVAL,
249                             (byte) params.getInterFrameInterval());
250         }
251 
252         if (mUwbInjector.getDeviceConfigFacade().isAntennaModeConfigSupported()) {
253             tlvBufferBuilder.putByte(ConfigParam.ANTENNA_MODE, params.getAntennaMode());
254         }
255         return tlvBufferBuilder.build();
256     }
257 
isTimeScheduledTwrSession(int scheduledMode, int rangingUsage)258     private boolean isTimeScheduledTwrSession(int scheduledMode, int rangingUsage) {
259         if (scheduledMode == FiraParams.TIME_SCHEDULED_RANGING) {
260             if (rangingUsage == FiraParams.RANGING_ROUND_USAGE_SS_TWR_DEFERRED_MODE
261                     || rangingUsage == FiraParams.RANGING_ROUND_USAGE_DS_TWR_DEFERRED_MODE
262                     || rangingUsage == FiraParams.RANGING_ROUND_USAGE_SS_TWR_NON_DEFERRED_MODE
263                     || rangingUsage == FiraParams.RANGING_ROUND_USAGE_DS_TWR_NON_DEFERRED_MODE) {
264                 return true;
265             }
266         }
267         return false;
268     }
269 
configureStsParameters(TlvBuffer.Builder tlvBufferBuilder, FiraOpenSessionParams params)270     private void configureStsParameters(TlvBuffer.Builder tlvBufferBuilder,
271         FiraOpenSessionParams params) {
272         int stsConfig = params.getStsConfig();
273 
274         if (stsConfig == FiraParams.STS_CONFIG_STATIC) {
275              tlvBufferBuilder
276                     .putByteArray(ConfigParam.VENDOR_ID, params.getVendorId() != null
277                             ? getComputedVendorId(params.getVendorId()): null)
278                     .putByteArray(ConfigParam.STATIC_STS_IV, params.getStaticStsIV());
279         } else if (stsConfig == FiraParams.STS_CONFIG_DYNAMIC_FOR_CONTROLEE_INDIVIDUAL_KEY) {
280             if (params.getDeviceType() == FiraParams.RANGING_DEVICE_TYPE_CONTROLEE) {
281                 tlvBufferBuilder.putInt(ConfigParam.SUB_SESSION_ID, params.getSubSessionId());
282             }
283         } else if (stsConfig == FiraParams.STS_CONFIG_PROVISIONED) {
284             if (params.getSessionKey() != null ) {
285                 tlvBufferBuilder.putByteArray(ConfigParam.SESSION_KEY, params.getSessionKey());
286             }
287         } else if (stsConfig == FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY) {
288             if (params.getDeviceType() == FiraParams.RANGING_DEVICE_TYPE_CONTROLEE) {
289                 tlvBufferBuilder.putInt(ConfigParam.SUB_SESSION_ID, params.getSubSessionId());
290                 if (params.getSubsessionKey() != null ) {
291                     tlvBufferBuilder.
292                           putByteArray(ConfigParam.SUBSESSION_KEY, params.getSubsessionKey());
293                 }
294             }
295             if (params.getSessionKey() != null ) {
296                 tlvBufferBuilder.putByteArray(ConfigParam.SESSION_KEY, params.getSessionKey());
297             }
298         }
299     }
300 
getUlTdoaDeviceId(int ulTdoaDeviceIdType, byte[] ulTdoaDeviceId)301     private byte[] getUlTdoaDeviceId(int ulTdoaDeviceIdType, byte[] ulTdoaDeviceId) {
302         if (ulTdoaDeviceIdType == FiraParams.UL_TDOA_DEVICE_ID_NONE) {
303             // Device ID not included
304             return new byte[]{0};
305         }
306         ByteBuffer buffer = ByteBuffer.allocate(ulTdoaDeviceId.length + 1);
307         buffer.put((byte) ulTdoaDeviceIdType);
308         buffer.put(ulTdoaDeviceId);
309         return buffer.array();
310     }
311 
getTlvBufferFromFiraRangingReconfigureParams(Params baseParam)312     private TlvBuffer getTlvBufferFromFiraRangingReconfigureParams(Params baseParam) {
313         FiraRangingReconfigureParams params = (FiraRangingReconfigureParams) baseParam;
314         TlvBuffer.Builder tlvBuilder = new TlvBuffer.Builder();
315         Integer blockStrideLength = params.getBlockStrideLength();
316         Integer rangeDataNtfConfig = params.getRangeDataNtfConfig();
317         Integer rangeDataProximityNear = params.getRangeDataProximityNear();
318         Integer rangeDataProximityFar = params.getRangeDataProximityFar();
319         Double rangeDataAoaAzimuthLower = params.getRangeDataAoaAzimuthLower();
320         Double rangeDataAoaAzimuthUpper = params.getRangeDataAoaAzimuthUpper();
321         Double rangeDataAoaElevationLower = params.getRangeDataAoaElevationLower();
322         Double rangeDataAoaElevationUpper = params.getRangeDataAoaElevationUpper();
323         Integer suspendRangingRounds = params.getSuspendRangingRounds();
324 
325         if (blockStrideLength != null) {
326             tlvBuilder.putByte(ConfigParam.BLOCK_STRIDE_LENGTH,
327                     (byte) blockStrideLength.intValue());
328         }
329 
330         if (rangeDataNtfConfig != null) {
331             tlvBuilder.putByte(ConfigParam.RANGE_DATA_NTF_CONFIG,
332                     (byte) rangeDataNtfConfig.intValue());
333         }
334 
335         if (rangeDataProximityNear != null) {
336             tlvBuilder.putShort(ConfigParam.RANGE_DATA_NTF_PROXIMITY_NEAR,
337                     (short) rangeDataProximityNear.intValue());
338         }
339 
340         if (rangeDataProximityFar != null) {
341             tlvBuilder.putShort(ConfigParam.RANGE_DATA_NTF_PROXIMITY_FAR,
342                     (short) rangeDataProximityFar.intValue());
343         }
344 
345         if (rangeDataNtfConfig != null && hasAoaBoundInRangeDataNtfConfig(rangeDataNtfConfig)) {
346             if ((rangeDataAoaAzimuthLower != null && rangeDataAoaAzimuthUpper != null)
347                     || (rangeDataAoaElevationLower != null && rangeDataAoaElevationUpper != null)) {
348                 rangeDataAoaAzimuthLower = rangeDataAoaAzimuthLower != null
349                         ? rangeDataAoaAzimuthLower
350                         : FiraParams.RANGE_DATA_NTF_AOA_AZIMUTH_LOWER_DEFAULT;
351                 rangeDataAoaAzimuthUpper = rangeDataAoaAzimuthUpper != null
352                         ? rangeDataAoaAzimuthUpper
353                         : FiraParams.RANGE_DATA_NTF_AOA_AZIMUTH_UPPER_DEFAULT;
354                 rangeDataAoaElevationLower = rangeDataAoaElevationLower != null
355                         ? rangeDataAoaElevationLower
356                         : FiraParams.RANGE_DATA_NTF_AOA_ELEVATION_LOWER_DEFAULT;
357                 rangeDataAoaElevationUpper = rangeDataAoaElevationUpper != null
358                         ? rangeDataAoaElevationUpper
359                         : FiraParams.RANGE_DATA_NTF_AOA_ELEVATION_UPPER_DEFAULT;
360                 tlvBuilder.putShortArray(ConfigParam.RANGE_DATA_NTF_AOA_BOUND, new short[]{
361                         // TODO (b/235355249): Verify this conversion. This is using AOA value
362                         // in UwbTwoWayMeasurement to external RangingMeasurement conversion as
363                         // reference.
364                         (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
365                                 UwbUtil.radianTodegree(
366                                         rangeDataAoaAzimuthLower.floatValue()), 9, 7), 16),
367                         (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
368                                 UwbUtil.radianTodegree(
369                                         rangeDataAoaAzimuthUpper.floatValue()), 9, 7), 16),
370                         (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
371                                 UwbUtil.radianTodegree(
372                                         rangeDataAoaElevationLower.floatValue()), 9, 7), 16),
373                         (short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
374                                 UwbUtil.radianTodegree(
375                                         rangeDataAoaElevationUpper.floatValue()), 9, 7), 16),
376                 });
377             }
378         }
379         if (suspendRangingRounds != null) {
380                 tlvBuilder.putByte(ConfigParam.SUSPEND_RANGING_ROUNDS,
381                         (byte) suspendRangingRounds.intValue());
382         }
383         return tlvBuilder.build();
384     }
385 
386     // Merged data from other parameter values
getResultReportConfig(FiraOpenSessionParams params)387     private int getResultReportConfig(FiraOpenSessionParams params) {
388         int resultReportConfig = 0x00;
389         resultReportConfig |= params.hasTimeOfFlightReport() ? 0x01 : 0x00;
390         resultReportConfig |= params.hasAngleOfArrivalAzimuthReport() ? 0x02 : 0x00;
391         resultReportConfig |= params.hasAngleOfArrivalElevationReport() ? 0x04 : 0x00;
392         resultReportConfig |= params.hasAngleOfArrivalFigureOfMeritReport() ? 0x08 : 0x00;
393         return resultReportConfig;
394     }
395 
getRangingRoundControl(FiraOpenSessionParams params)396     private int getRangingRoundControl(FiraOpenSessionParams params) {
397         // RANGING_ROUND_CONTROL
398         byte rangingRoundControl = 0x00;
399 
400         // b0 : Ranging Result Report Message
401         rangingRoundControl |= (byte) (params.hasRangingResultReportMessage() ? 0x01 : 0x00);
402 
403         // b1 : Control Message
404         rangingRoundControl |= (byte) (params.hasControlMessage() ? 0x02 : 0x00);
405 
406         // b2 : Ranging Control Phase
407         rangingRoundControl |= (byte) (params.hasRangingControlPhase() ? 0x04 : 0x00);
408 
409         // b6 : Measurement Report Message
410         if (params.getScheduledMode() == FiraParams.CONTENTION_BASED_RANGING) {
411             if (params.getMeasurementReportPhase() == FiraParams.MEASUREMENT_REPORT_PHASE_SET) {
412                 rangingRoundControl |= (byte) 0x40;
413             }
414         }
415 
416         // b7 : Measurement Report Message
417         if (params.getMeasurementReportType()
418                 == FiraParams.MEASUREMENT_REPORT_TYPE_RESPONDER_TO_INITIATOR) {
419             rangingRoundControl |= (byte) 0x80;
420         }
421         return rangingRoundControl;
422     }
423 
getComputedMacAddress(UwbAddress address)424     private static byte[] getComputedMacAddress(UwbAddress address) {
425         if (!SdkLevel.isAtLeastU()) {
426             return TlvUtil.getReverseBytes(address.toBytes());
427         }
428         return address.toBytes();
429     }
430 
getComputedVendorId(byte[] data)431     private static byte[] getComputedVendorId(byte[] data) {
432         if (!SdkLevel.isAtLeastU()) {
433             return TlvUtil.getReverseBytes(data);
434         }
435         return data;
436     }
437 
getSessionTimeBase(FiraOpenSessionParams params)438     private byte[] getSessionTimeBase(FiraOpenSessionParams params) {
439         byte[] sessionTimeBaseParam = new byte[FiraParams.SESSION_TIME_BASE_PARAM_LEN];
440         int offset = 0;
441         sessionTimeBaseParam[offset++] = (byte) params.getReferenceTimeBase();
442         byte[] sessionHandleValue = TlvUtil.getBytes(params.getReferenceSessionHandle());
443         for (int index = FiraParams.SESSION_HANDLE_LEN - 1; index >= 0; index--) {
444             sessionTimeBaseParam[offset++] = (byte) sessionHandleValue[index];
445         }
446         byte[] sessionOffsetInMicroSecondValue =
447                 TlvUtil.getBytes(params.getSessionOffsetInMicroSeconds());
448         for (int index = FiraParams.SESSION_OFFSET_TIME_LEN - 1; index >= 0; index--) {
449             sessionTimeBaseParam[offset++] = (byte) sessionOffsetInMicroSecondValue[index];
450         }
451         return sessionTimeBaseParam;
452     }
453 }
454