• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.uwb.params;
18 
19 import static com.android.server.uwb.config.CapabilityParam.ALIRO_SUPPORTED_MAC_MODES;
20 import static com.android.server.uwb.config.CapabilityParam.CCC_CHANNEL_5;
21 import static com.android.server.uwb.config.CapabilityParam.CCC_CHANNEL_9;
22 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_12;
23 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_24;
24 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_3;
25 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_4;
26 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_6;
27 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_8;
28 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_9;
29 import static com.android.server.uwb.config.CapabilityParam.CCC_EXTENSION_HOPPING_MODE_ADAPTIVE_BITMASK;
30 import static com.android.server.uwb.config.CapabilityParam.CCC_EXTENSION_HOPPING_MODE_CONTINUOUS_BITMASK;
31 import static com.android.server.uwb.config.CapabilityParam.CCC_EXTENSION_HOPPING_MODE_NONE_BITMASK;
32 import static com.android.server.uwb.config.CapabilityParam.CCC_EXTENSION_HOPPING_SEQUENCE_AES_BITMASK;
33 import static com.android.server.uwb.config.CapabilityParam.CCC_EXTENSION_HOPPING_SEQUENCE_DEFAULT_BITMASK;
34 import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_CONFIG_MODE_ADAPTIVE;
35 import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_CONFIG_MODE_CONTINUOUS;
36 import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_CONFIG_MODE_NONE;
37 import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_SEQUENCE_AES;
38 import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_SEQUENCE_DEFAULT;
39 import static com.android.server.uwb.config.CapabilityParam.CCC_PRIORITIZED_CHANNEL_LIST;
40 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_CHANNELS;
41 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_CHAPS_PER_SLOT;
42 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_HOPPING_CONFIG_MODES_AND_SEQUENCES;
43 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER;
44 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS;
45 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_PULSE_SHAPE_COMBOS;
46 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_RAN_MULTIPLIER;
47 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_SYNC_CODES;
48 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_UWB_CONFIGS;
49 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_UWBS_MAX_PPM;
50 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_VERSIONS;
51 
52 import static com.google.uwb.support.aliro.AliroParams.CHAPS_PER_SLOT_12;
53 import static com.google.uwb.support.aliro.AliroParams.CHAPS_PER_SLOT_24;
54 import static com.google.uwb.support.aliro.AliroParams.CHAPS_PER_SLOT_3;
55 import static com.google.uwb.support.aliro.AliroParams.CHAPS_PER_SLOT_4;
56 import static com.google.uwb.support.aliro.AliroParams.CHAPS_PER_SLOT_6;
57 import static com.google.uwb.support.aliro.AliroParams.CHAPS_PER_SLOT_8;
58 import static com.google.uwb.support.aliro.AliroParams.CHAPS_PER_SLOT_9;
59 import static com.google.uwb.support.aliro.AliroParams.HOPPING_CONFIG_MODE_ADAPTIVE;
60 import static com.google.uwb.support.aliro.AliroParams.HOPPING_CONFIG_MODE_CONTINUOUS;
61 import static com.google.uwb.support.aliro.AliroParams.HOPPING_CONFIG_MODE_NONE;
62 import static com.google.uwb.support.aliro.AliroParams.HOPPING_SEQUENCE_AES;
63 import static com.google.uwb.support.aliro.AliroParams.HOPPING_SEQUENCE_DEFAULT;
64 import static com.google.uwb.support.aliro.AliroParams.UWB_CHANNEL_5;
65 import static com.google.uwb.support.aliro.AliroParams.UWB_CHANNEL_9;
66 
67 import android.util.Log;
68 
69 import com.android.server.uwb.UwbInjector;
70 import com.android.server.uwb.config.ConfigParam;
71 
72 import com.google.uwb.support.aliro.AliroProtocolVersion;
73 import com.google.uwb.support.aliro.AliroPulseShapeCombo;
74 import com.google.uwb.support.aliro.AliroRangingStartedParams;
75 import com.google.uwb.support.aliro.AliroRangingStoppedParams;
76 import com.google.uwb.support.aliro.AliroSpecificationParams;
77 import com.google.uwb.support.base.Params;
78 import com.google.uwb.support.base.ProtocolVersion;
79 
80 import java.nio.ByteBuffer;
81 import java.nio.ByteOrder;
82 
83 /**
84  * Aliro decoder - this started out as a copy of the CCC decoder.
85  */
86 public class AliroDecoder extends TlvDecoder {
87     private static final String TAG = "AliroDecoder";
88     private final UwbInjector mUwbInjector;
89 
AliroDecoder(UwbInjector uwbInjector)90     public AliroDecoder(UwbInjector uwbInjector) {
91         mUwbInjector = uwbInjector;
92     }
93 
94     @Override
getParams(TlvDecoderBuffer tlvs, Class<T> paramsType, ProtocolVersion protocolVersion)95     public <T extends Params> T getParams(TlvDecoderBuffer tlvs, Class<T> paramsType,
96             ProtocolVersion protocolVersion)
97             throws IllegalArgumentException {
98         if (AliroRangingStartedParams.class.equals(paramsType)) {
99             return (T) getAliroRangingStartedParamsFromTlvBuffer(tlvs);
100         }
101         if (AliroSpecificationParams.class.equals(paramsType)) {
102             return (T) getAliroSpecificationParamsFromTlvBuffer(tlvs);
103         }
104         if (AliroRangingStoppedParams.class.equals(paramsType)) {
105             return (T) getAliroRangingStoppedParamsFromTlvBuffer(tlvs);
106         }
107         return null;
108     }
109 
isBitSet(int flags, int mask)110     private static boolean isBitSet(int flags, int mask) {
111         return (flags & mask) != 0;
112     }
113 
getAliroRangingStartedParamsFromTlvBuffer( TlvDecoderBuffer tlvs)114     private AliroRangingStartedParams getAliroRangingStartedParamsFromTlvBuffer(
115             TlvDecoderBuffer tlvs) {
116         byte[] hopModeKey = tlvs.getByteArray(ConfigParam.HOP_MODE_KEY);
117         int hopModeKeyInt = ByteBuffer.wrap(hopModeKey).order(ByteOrder.LITTLE_ENDIAN).getInt();
118         long uwbTime0;
119         // Backwards compatibility with vendors who were using Google defined
120         // UWB_TIME0 TLV param.
121         try {
122             uwbTime0 = tlvs.getLong(ConfigParam.UWB_TIME0);
123         } catch (IllegalArgumentException e) {
124             uwbTime0 = tlvs.getLong(ConfigParam.UWB_INITIATION_TIME);
125         }
126 
127         return new AliroRangingStartedParams.Builder()
128                 // STS_Index0  0 - 0x3FFFFFFFF
129                 .setStartingStsIndex(tlvs.getInt(ConfigParam.STS_INDEX))
130                 .setHopModeKey(hopModeKeyInt)
131                 //  UWB_Time0 0 - 0xFFFFFFFFFFFFFFFF  UWB_INITIATION_TIME
132                 .setUwbTime0(uwbTime0)
133                 // RANGING_INTERVAL = RAN_Multiplier * 96
134                 .setRanMultiplier(tlvs.getInt(ConfigParam.RANGING_INTERVAL) / 96)
135                 .setSyncCodeIndex(tlvs.getByte(ConfigParam.PREAMBLE_CODE_INDEX))
136                 .build();
137     }
138 
getAliroSpecificationParamsFromTlvBuffer( TlvDecoderBuffer tlvs)139     private AliroSpecificationParams getAliroSpecificationParamsFromTlvBuffer(
140             TlvDecoderBuffer tlvs) {
141         AliroSpecificationParams.Builder builder = new AliroSpecificationParams.Builder();
142         byte[] versions = tlvs.getByteArray(CCC_SUPPORTED_VERSIONS);
143         if (versions.length % 2 != 0) {
144             throw new IllegalArgumentException("Invalid supported protocol versions len "
145                     + versions.length);
146         }
147         for (int i = 0; i < versions.length; i += 2) {
148             builder.addProtocolVersion(AliroProtocolVersion.fromBytes(versions, i));
149         }
150         byte[] configs = tlvs.getByteArray(CCC_SUPPORTED_UWB_CONFIGS);
151         for (int i = 0; i < configs.length; i++) {
152             builder.addUwbConfig(configs[i]);
153         }
154         byte[] pulse_shape_combos = tlvs.getByteArray(CCC_SUPPORTED_PULSE_SHAPE_COMBOS);
155         for (int i = 0; i < pulse_shape_combos.length; i++) {
156             builder.addPulseShapeCombo(AliroPulseShapeCombo.fromBytes(pulse_shape_combos, i));
157         }
158         builder.setRanMultiplier(tlvs.getInt(CCC_SUPPORTED_RAN_MULTIPLIER));
159         byte chapsPerslot = tlvs.getByte(CCC_SUPPORTED_CHAPS_PER_SLOT);
160         if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_3)) {
161             builder.addChapsPerSlot(CHAPS_PER_SLOT_3);
162         }
163         if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_4)) {
164             builder.addChapsPerSlot(CHAPS_PER_SLOT_4);
165         }
166         if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_6)) {
167             builder.addChapsPerSlot(CHAPS_PER_SLOT_6);
168         }
169         if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_8)) {
170             builder.addChapsPerSlot(CHAPS_PER_SLOT_8);
171         }
172         if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_9)) {
173             builder.addChapsPerSlot(CHAPS_PER_SLOT_9);
174         }
175         if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_12)) {
176             builder.addChapsPerSlot(CHAPS_PER_SLOT_12);
177         }
178         if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_24)) {
179             builder.addChapsPerSlot(CHAPS_PER_SLOT_24);
180         }
181         // TODO(b/321757248): Consider replacing with an Aliro flag.
182         if (mUwbInjector.getDeviceConfigFacade().isCccSupportedSyncCodesLittleEndian()) {
183             byte[] syncCodes = tlvs.getByteArray(CCC_SUPPORTED_SYNC_CODES);
184             for (int byteIndex = 0; byteIndex < syncCodes.length; byteIndex++) {
185                 byte syncCodeByte = syncCodes[byteIndex];
186                 for (int bitIndex = 0; bitIndex < 8; bitIndex++) {
187                     if ((syncCodeByte & (1 << bitIndex)) != 0) {
188                         int syncCodeValue = (byteIndex * 8) + bitIndex + 1;
189                         builder.addSyncCode(syncCodeValue);
190                     }
191                 }
192             }
193         } else {
194             int syncCodes = ByteBuffer.wrap(tlvs.getByteArray(CCC_SUPPORTED_SYNC_CODES)).getInt();
195             for (int i = 0; i < 32; i++) {
196                 if (isBitSet(syncCodes, 1 << i)) {
197                     builder.addSyncCode(i + 1);
198                 }
199             }
200         }
201 
202         try {
203             byte[] prioritizedChannels = tlvs.getByteArray(CCC_PRIORITIZED_CHANNEL_LIST);
204             byte channels = tlvs.getByte(CCC_SUPPORTED_CHANNELS);
205             for (byte prioritizedChannel : prioritizedChannels) {
206                 if (isBitSet(channels, CCC_CHANNEL_5) && prioritizedChannel == UWB_CHANNEL_5) {
207                     builder.addChannel(prioritizedChannel);
208                 }
209                 if (isBitSet(channels, CCC_CHANNEL_9) && prioritizedChannel == UWB_CHANNEL_9) {
210                     builder.addChannel(prioritizedChannel);
211                 }
212             }
213         } catch (IllegalArgumentException e) {
214             Log.w(TAG, "CCC_PRIORITIZED_CHANNEL_LIST not found");
215             byte channels = tlvs.getByte(CCC_SUPPORTED_CHANNELS);
216             if (isBitSet(channels, CCC_CHANNEL_5)) {
217                 builder.addChannel(UWB_CHANNEL_5);
218             }
219             if (isBitSet(channels, CCC_CHANNEL_9)) {
220                 builder.addChannel(UWB_CHANNEL_9);
221             }
222         }
223 
224         boolean isFiraExtensionSupported =
225                 mUwbInjector.getDeviceConfigFacade().isFiraSupportedExtensionForCCC();
226         byte hoppingConfigModesAndSequences =
227                 tlvs.getByte(CCC_SUPPORTED_HOPPING_CONFIG_MODES_AND_SEQUENCES);
228         if (isBitSet(hoppingConfigModesAndSequences,
229                 isFiraExtensionSupported
230                         ? CCC_EXTENSION_HOPPING_MODE_NONE_BITMASK :
231                         CCC_HOPPING_CONFIG_MODE_NONE)) {
232             builder.addHoppingConfigMode(HOPPING_CONFIG_MODE_NONE);
233         }
234         if (isBitSet(hoppingConfigModesAndSequences,
235                 isFiraExtensionSupported
236                         ? CCC_EXTENSION_HOPPING_MODE_CONTINUOUS_BITMASK :
237                         CCC_HOPPING_CONFIG_MODE_CONTINUOUS)) {
238             builder.addHoppingConfigMode(HOPPING_CONFIG_MODE_CONTINUOUS);
239         }
240         if (isBitSet(hoppingConfigModesAndSequences,
241                 isFiraExtensionSupported
242                         ? CCC_EXTENSION_HOPPING_MODE_ADAPTIVE_BITMASK :
243                         CCC_HOPPING_CONFIG_MODE_ADAPTIVE)) {
244             builder.addHoppingConfigMode(HOPPING_CONFIG_MODE_ADAPTIVE);
245         }
246         if (isBitSet(hoppingConfigModesAndSequences,
247                 isFiraExtensionSupported
248                         ? CCC_EXTENSION_HOPPING_SEQUENCE_AES_BITMASK :
249                         CCC_HOPPING_SEQUENCE_AES)) {
250             builder.addHoppingSequence(HOPPING_SEQUENCE_AES);
251         }
252         if (isBitSet(hoppingConfigModesAndSequences,
253                 isFiraExtensionSupported
254                         ? CCC_EXTENSION_HOPPING_SEQUENCE_DEFAULT_BITMASK :
255                         CCC_HOPPING_SEQUENCE_DEFAULT)) {
256             builder.addHoppingSequence(HOPPING_SEQUENCE_DEFAULT);
257         }
258 
259         try {
260             int maxRangingSessionNumber = tlvs.getInt(CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER);
261             builder.setMaxRangingSessionNumber(maxRangingSessionNumber);
262         } catch (IllegalArgumentException e) {
263             Log.w(TAG, "SUPPORTED_MAX_RANGING_SESSION_NUMBER not found");
264         }
265 
266         try {
267             int minUwbInitiationTimeMs = tlvs.getInt(CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS);
268             builder.setMinUwbInitiationTimeMs(minUwbInitiationTimeMs);
269         } catch (IllegalArgumentException e) {
270             Log.w(TAG, "SUPPORTED_MIN_UWB_INITIATION_TIME_MS not found");
271         }
272 
273         // Attempt to parse the UWBS_MAX_PPM as a short, since the CCC spec R3 defines the
274         // field Device_max_PPM field (in the TimeSync message) as a 2-octet field.
275         try {
276             short uwbsMaxPPM = tlvs.getShort(CCC_SUPPORTED_UWBS_MAX_PPM);
277             builder.setUwbsMaxPPM(uwbsMaxPPM);
278         } catch (IllegalArgumentException e) {
279             Log.w(TAG, "CCC_SUPPORTED_UWBS_MAX_PPM not found");
280         }
281         try {
282             byte[] modes = tlvs.getByteArray(ALIRO_SUPPORTED_MAC_MODES);
283             for (int i = 0; i < modes.length; i++) {
284                 builder.addMacMode(modes[i]);
285             }
286         } catch (IllegalArgumentException e) {
287             Log.w(TAG, "ALIRO_SUPPORTED_MAC_MODES not found");
288         }
289 
290         return builder.build();
291     }
292 
getAliroRangingStoppedParamsFromTlvBuffer( TlvDecoderBuffer tlvs)293     private AliroRangingStoppedParams getAliroRangingStoppedParamsFromTlvBuffer(
294             TlvDecoderBuffer tlvs) {
295         int lastStsIndexUsed = tlvs.getInt(ConfigParam.LAST_STS_INDEX_USED);
296         return new AliroRangingStoppedParams.Builder()
297                 .setLastStsIndexUsed(lastStsIndexUsed)
298                 .build();
299     }
300 }
301