• 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.android.server.uwb.config.CapabilityParam.CCC_CHANNEL_5;
20 import static com.android.server.uwb.config.CapabilityParam.CCC_CHANNEL_9;
21 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_12;
22 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_24;
23 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_3;
24 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_4;
25 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_6;
26 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_8;
27 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_9;
28 import static com.android.server.uwb.config.CapabilityParam.CCC_EXTENSION_HOPPING_MODE_ADAPTIVE_BITMASK;
29 import static com.android.server.uwb.config.CapabilityParam.CCC_EXTENSION_HOPPING_MODE_CONTINUOUS_BITMASK;
30 import static com.android.server.uwb.config.CapabilityParam.CCC_EXTENSION_HOPPING_MODE_NONE_BITMASK;
31 import static com.android.server.uwb.config.CapabilityParam.CCC_EXTENSION_HOPPING_SEQUENCE_AES_BITMASK;
32 import static com.android.server.uwb.config.CapabilityParam.CCC_EXTENSION_HOPPING_SEQUENCE_DEFAULT_BITMASK;
33 import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_CONFIG_MODE_ADAPTIVE;
34 import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_CONFIG_MODE_CONTINUOUS;
35 import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_CONFIG_MODE_NONE;
36 import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_SEQUENCE_AES;
37 import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_SEQUENCE_DEFAULT;
38 import static com.android.server.uwb.config.CapabilityParam.CCC_PRIORITIZED_CHANNEL_LIST;
39 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_CHANNELS;
40 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_CHAPS_PER_SLOT;
41 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_HOPPING_CONFIG_MODES_AND_SEQUENCES;
42 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER;
43 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS;
44 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_PULSE_SHAPE_COMBOS;
45 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_RAN_MULTIPLIER;
46 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_SYNC_CODES;
47 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_UWB_CONFIGS;
48 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_UWBS_MAX_PPM;
49 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_VERSIONS;
50 
51 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_12;
52 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_24;
53 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_3;
54 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_4;
55 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_6;
56 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_8;
57 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_9;
58 import static com.google.uwb.support.ccc.CccParams.HOPPING_CONFIG_MODE_ADAPTIVE;
59 import static com.google.uwb.support.ccc.CccParams.HOPPING_CONFIG_MODE_CONTINUOUS;
60 import static com.google.uwb.support.ccc.CccParams.HOPPING_CONFIG_MODE_NONE;
61 import static com.google.uwb.support.ccc.CccParams.HOPPING_SEQUENCE_AES;
62 import static com.google.uwb.support.ccc.CccParams.HOPPING_SEQUENCE_DEFAULT;
63 import static com.google.uwb.support.ccc.CccParams.UWB_CHANNEL_5;
64 import static com.google.uwb.support.ccc.CccParams.UWB_CHANNEL_9;
65 
66 import android.util.Log;
67 
68 import com.android.server.uwb.UwbInjector;
69 import com.android.server.uwb.config.ConfigParam;
70 
71 import com.google.uwb.support.base.Params;
72 import com.google.uwb.support.base.ProtocolVersion;
73 import com.google.uwb.support.ccc.CccProtocolVersion;
74 import com.google.uwb.support.ccc.CccPulseShapeCombo;
75 import com.google.uwb.support.ccc.CccRangingStartedParams;
76 import com.google.uwb.support.ccc.CccRangingStoppedParams;
77 import com.google.uwb.support.ccc.CccSpecificationParams;
78 
79 import java.nio.ByteBuffer;
80 import java.nio.ByteOrder;
81 
82 /**
83  * CCC decoder
84  */
85 public class CccDecoder extends TlvDecoder {
86     private static final String TAG = "CccDecoder";
87     private final UwbInjector mUwbInjector;
88 
CccDecoder(UwbInjector uwbInjector)89     public CccDecoder(UwbInjector uwbInjector) {
90         mUwbInjector = uwbInjector;
91     }
92 
93     @Override
getParams(TlvDecoderBuffer tlvs, Class<T> paramsType, ProtocolVersion protocolVersion)94     public <T extends Params> T getParams(TlvDecoderBuffer tlvs, Class<T> paramsType,
95             ProtocolVersion protocolVersion)
96             throws IllegalArgumentException {
97         if (CccRangingStartedParams.class.equals(paramsType)) {
98             return (T) getCccRangingStartedParamsFromTlvBuffer(tlvs);
99         }
100         if (CccSpecificationParams.class.equals(paramsType)) {
101             return (T) getCccSpecificationParamsFromTlvBuffer(tlvs);
102         }
103         if (CccRangingStoppedParams.class.equals(paramsType)) {
104             return (T) getCccRangingStoppedParamsFromTlvBuffer(tlvs);
105         }
106         return null;
107     }
108 
isBitSet(int flags, int mask)109     private static boolean isBitSet(int flags, int mask) {
110         return (flags & mask) != 0;
111     }
112 
getCccRangingStartedParamsFromTlvBuffer(TlvDecoderBuffer tlvs)113     private CccRangingStartedParams getCccRangingStartedParamsFromTlvBuffer(TlvDecoderBuffer tlvs) {
114         byte[] hopModeKey = tlvs.getByteArray(ConfigParam.HOP_MODE_KEY);
115         int hopModeKeyInt = ByteBuffer.wrap(hopModeKey).order(ByteOrder.LITTLE_ENDIAN).getInt();
116         long uwbTime0;
117         // Backwards compatibility with vendors who were using Google defined
118         // UWB_TIME0 TLV param.
119         try {
120             uwbTime0 = tlvs.getLong(ConfigParam.UWB_TIME0);
121         } catch (IllegalArgumentException e) {
122             uwbTime0 = tlvs.getLong(ConfigParam.UWB_INITIATION_TIME);
123         }
124 
125         return new CccRangingStartedParams.Builder()
126                 // STS_Index0  0 - 0x3FFFFFFFF
127                 .setStartingStsIndex(tlvs.getInt(ConfigParam.STS_INDEX))
128                 .setHopModeKey(hopModeKeyInt)
129                 //  UWB_Time0 0 - 0xFFFFFFFFFFFFFFFF  UWB_INITIATION_TIME
130                 .setUwbTime0(uwbTime0)
131                 // RANGING_INTERVAL = RAN_Multiplier * 96
132                 .setRanMultiplier(tlvs.getInt(ConfigParam.RANGING_INTERVAL) / 96)
133                 .setSyncCodeIndex(tlvs.getByte(ConfigParam.PREAMBLE_CODE_INDEX))
134                 .build();
135     }
136 
getCccSpecificationParamsFromTlvBuffer(TlvDecoderBuffer tlvs)137     private CccSpecificationParams getCccSpecificationParamsFromTlvBuffer(TlvDecoderBuffer tlvs) {
138         CccSpecificationParams.Builder builder = new CccSpecificationParams.Builder();
139         byte[] versions = tlvs.getByteArray(CCC_SUPPORTED_VERSIONS);
140         if (versions.length % 2 != 0) {
141             throw new IllegalArgumentException("Invalid supported protocol versions len "
142                     + versions.length);
143         }
144         for (int i = 0; i < versions.length; i += 2) {
145             builder.addProtocolVersion(CccProtocolVersion.fromBytes(versions, i));
146         }
147         byte[] configs = tlvs.getByteArray(CCC_SUPPORTED_UWB_CONFIGS);
148         if (mUwbInjector.isCccSupportedTwoByteConfigIdLittleEndian()) {
149             if (configs.length % 2 != 0) {
150                 throw new IllegalArgumentException("Invalid supported configs len "
151                         + versions.length);
152             }
153             for (int i = 0; i < configs.length; i += 2) {
154                 int config = ((configs[i + 1] & 0xff) << 8) + (configs[i] & 0xff);
155                 builder.addUwbConfig(config);
156             }
157         } else {
158             for (int i = 0; i < configs.length; i++) {
159                 builder.addUwbConfig(configs[i]);
160             }
161         }
162 
163         byte[] pulse_shape_combos = tlvs.getByteArray(CCC_SUPPORTED_PULSE_SHAPE_COMBOS);
164         for (int i = 0; i < pulse_shape_combos.length; i++) {
165             builder.addPulseShapeCombo(CccPulseShapeCombo.fromBytes(pulse_shape_combos, i));
166         }
167         int supportedRanMultiplier;
168         try {
169             supportedRanMultiplier = tlvs.getInt(CCC_SUPPORTED_RAN_MULTIPLIER);
170         } catch (IllegalArgumentException e) {
171             Log.w(TAG, "CCC_SUPPORTED_RAN_MULTIPLIER not a 4 byte value");
172             // Try for single byte
173             supportedRanMultiplier = tlvs.getByte(CCC_SUPPORTED_RAN_MULTIPLIER);
174         }
175         builder.setRanMultiplier(supportedRanMultiplier);
176 
177         byte chapsPerslot = tlvs.getByte(CCC_SUPPORTED_CHAPS_PER_SLOT);
178         if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_3)) {
179             builder.addChapsPerSlot(CHAPS_PER_SLOT_3);
180         }
181         if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_4)) {
182             builder.addChapsPerSlot(CHAPS_PER_SLOT_4);
183         }
184         if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_6)) {
185             builder.addChapsPerSlot(CHAPS_PER_SLOT_6);
186         }
187         if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_8)) {
188             builder.addChapsPerSlot(CHAPS_PER_SLOT_8);
189         }
190         if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_9)) {
191             builder.addChapsPerSlot(CHAPS_PER_SLOT_9);
192         }
193         if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_12)) {
194             builder.addChapsPerSlot(CHAPS_PER_SLOT_12);
195         }
196         if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_24)) {
197             builder.addChapsPerSlot(CHAPS_PER_SLOT_24);
198         }
199         if (mUwbInjector.getDeviceConfigFacade().isCccSupportedSyncCodesLittleEndian()) {
200             byte[] syncCodes = tlvs.getByteArray(CCC_SUPPORTED_SYNC_CODES);
201             for (int byteIndex = 0; byteIndex < syncCodes.length; byteIndex++) {
202                 byte syncCodeByte = syncCodes[byteIndex];
203                 for (int bitIndex = 0; bitIndex < 8; bitIndex++) {
204                     if ((syncCodeByte & (1 << bitIndex)) != 0) {
205                         int syncCodeValue = (byteIndex * 8) + bitIndex + 1;
206                         builder.addSyncCode(syncCodeValue);
207                     }
208                 }
209             }
210         } else {
211             int syncCodes = ByteBuffer.wrap(tlvs.getByteArray(CCC_SUPPORTED_SYNC_CODES)).getInt();
212             for (int i = 0; i < 32; i++) {
213                 if (isBitSet(syncCodes, 1 << i)) {
214                     builder.addSyncCode(i + 1);
215                 }
216             }
217         }
218 
219         try {
220             byte[] prioritizedChannels = tlvs.getByteArray(CCC_PRIORITIZED_CHANNEL_LIST);
221             byte channels = tlvs.getByte(CCC_SUPPORTED_CHANNELS);
222             for (byte prioritizedChannel : prioritizedChannels) {
223                 if (isBitSet(channels, CCC_CHANNEL_5) && prioritizedChannel == UWB_CHANNEL_5) {
224                     builder.addChannel(prioritizedChannel);
225                 }
226                 if (isBitSet(channels, CCC_CHANNEL_9) && prioritizedChannel == UWB_CHANNEL_9) {
227                     builder.addChannel(prioritizedChannel);
228                 }
229             }
230         } catch (IllegalArgumentException e) {
231             Log.w(TAG, "CCC_PRIORITIZED_CHANNEL_LIST not found");
232             byte channels = tlvs.getByte(CCC_SUPPORTED_CHANNELS);
233             if (isBitSet(channels, CCC_CHANNEL_5)) {
234                 builder.addChannel(UWB_CHANNEL_5);
235             }
236             if (isBitSet(channels, CCC_CHANNEL_9)) {
237                 builder.addChannel(UWB_CHANNEL_9);
238             }
239         }
240         boolean isFiraExtensionSupported =
241                 mUwbInjector.getDeviceConfigFacade().isFiraSupportedExtensionForCCC();
242         byte hoppingConfigModesAndSequences =
243                 tlvs.getByte(CCC_SUPPORTED_HOPPING_CONFIG_MODES_AND_SEQUENCES);
244         if (isBitSet(hoppingConfigModesAndSequences,
245                 isFiraExtensionSupported
246                         ? CCC_EXTENSION_HOPPING_MODE_NONE_BITMASK :
247                         CCC_HOPPING_CONFIG_MODE_NONE)) {
248             builder.addHoppingConfigMode(HOPPING_CONFIG_MODE_NONE);
249         }
250         if (isBitSet(hoppingConfigModesAndSequences,
251                 isFiraExtensionSupported
252                         ? CCC_EXTENSION_HOPPING_MODE_CONTINUOUS_BITMASK :
253                         CCC_HOPPING_CONFIG_MODE_CONTINUOUS)) {
254             builder.addHoppingConfigMode(HOPPING_CONFIG_MODE_CONTINUOUS);
255         }
256         if (isBitSet(hoppingConfigModesAndSequences,
257                 isFiraExtensionSupported
258                         ? CCC_EXTENSION_HOPPING_MODE_ADAPTIVE_BITMASK :
259                         CCC_HOPPING_CONFIG_MODE_ADAPTIVE)) {
260             builder.addHoppingConfigMode(HOPPING_CONFIG_MODE_ADAPTIVE);
261         }
262         if (isBitSet(hoppingConfigModesAndSequences,
263                 isFiraExtensionSupported
264                         ? CCC_EXTENSION_HOPPING_SEQUENCE_AES_BITMASK :
265                         CCC_HOPPING_SEQUENCE_AES)) {
266             builder.addHoppingSequence(HOPPING_SEQUENCE_AES);
267         }
268         if (isBitSet(hoppingConfigModesAndSequences,
269                 isFiraExtensionSupported
270                         ? CCC_EXTENSION_HOPPING_SEQUENCE_DEFAULT_BITMASK :
271                         CCC_HOPPING_SEQUENCE_DEFAULT)) {
272             builder.addHoppingSequence(HOPPING_SEQUENCE_DEFAULT);
273         }
274 
275         try {
276             int maxRangingSessionNumber = tlvs.getInt(CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER);
277             builder.setMaxRangingSessionNumber(maxRangingSessionNumber);
278         } catch (IllegalArgumentException e) {
279             Log.w(TAG, "SUPPORTED_MAX_RANGING_SESSION_NUMBER not found");
280         }
281 
282         try {
283             int minUwbInitiationTimeMs = tlvs.getInt(CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS);
284             builder.setMinUwbInitiationTimeMs(minUwbInitiationTimeMs);
285         } catch (IllegalArgumentException e) {
286             Log.w(TAG, "SUPPORTED_MIN_UWB_INITIATION_TIME_MS not found");
287         }
288 
289         // Attempt to parse the UWBS_MAX_PPM as a short, since the CCC spec R3 defines the
290         // field Device_max_PPM field (in the TimeSync message) as a 2-octet field.
291         try {
292             short uwbsMaxPPM = tlvs.getShort(CCC_SUPPORTED_UWBS_MAX_PPM);
293             builder.setUwbsMaxPPM(uwbsMaxPPM);
294         } catch (IllegalArgumentException e) {
295             Log.w(TAG, "CCC_SUPPORTED_UWBS_MAX_PPM not found");
296         }
297 
298         return builder.build();
299     }
300 
getCccRangingStoppedParamsFromTlvBuffer(TlvDecoderBuffer tlvs)301     private CccRangingStoppedParams getCccRangingStoppedParamsFromTlvBuffer(TlvDecoderBuffer tlvs) {
302         int lastStsIndexUsed = tlvs.getInt(ConfigParam.LAST_STS_INDEX_USED);
303         return new CccRangingStoppedParams.Builder()
304                 .setLastStsIndexUsed(lastStsIndexUsed)
305                 .build();
306     }
307 }
308