• 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.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