• 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.google.uwb.support.ccc;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 
21 import android.os.Build.VERSION_CODES;
22 import android.os.PersistableBundle;
23 import android.uwb.UwbManager;
24 
25 import androidx.annotation.IntRange;
26 import androidx.annotation.NonNull;
27 import androidx.annotation.Nullable;
28 import androidx.annotation.RequiresApi;
29 
30 import com.google.uwb.support.base.RequiredParam;
31 
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.List;
35 
36 /**
37  * Defines parameters for CCC capability reports
38  *
39  * <p>This is returned as a bundle from the service API {@link UwbManager#getSpecificationInfo}.
40  */
41 @RequiresApi(VERSION_CODES.LOLLIPOP)
42 public class CccSpecificationParams extends CccParams {
43     private static final int BUNDLE_VERSION_1 = 1;
44     private static final int BUNDLE_VERSION_CURRENT = BUNDLE_VERSION_1;
45 
46     private final List<CccProtocolVersion> mProtocolVersions;
47     @UwbConfig private final List<Integer> mUwbConfigs;
48     private final List<CccPulseShapeCombo> mPulseShapeCombos;
49     private final int mRanMultiplier;
50     private final int mMaxRangingSessionNumber;
51     private final int mMinUwbInitiationTimeMs;
52     @ChapsPerSlot private final List<Integer> mChapsPerSlot;
53     @SyncCodeIndex private final List<Integer> mSyncCodes;
54     @Channel private final List<Integer> mChannels;
55     @HoppingConfigMode private final List<Integer> mHoppingConfigModes;
56     @HoppingSequence private final List<Integer> mHoppingSequences;
57 
58     private static final String KEY_PROTOCOL_VERSIONS = "protocol_versions";
59     private static final String KEY_UWB_CONFIGS = "uwb_configs";
60     private static final String KEY_PULSE_SHAPE_COMBOS = "pulse_shape_combos";
61     private static final String KEY_RAN_MULTIPLIER = "ran_multiplier";
62     private static final String KEY_MAX_RANGING_SESSION_NUMBER = "max_ranging_session_number";
63     private static final String KEY_MIN_UWB_INITIATION_TIME_MS = "min_uwb_initiation_time_ms";
64     private static final String KEY_CHAPS_PER_SLOTS = "chaps_per_slots";
65     private static final String KEY_SYNC_CODES = "sync_codes";
66     private static final String KEY_CHANNELS = "channels";
67     private static final String KEY_HOPPING_CONFIGS = "hopping_config_modes";
68     private static final String KEY_HOPPING_SEQUENCES = "hopping_sequences";
69 
70     public static final int DEFAULT_MAX_RANGING_SESSIONS_NUMBER = 1;
71 
CccSpecificationParams( List<CccProtocolVersion> protocolVersions, @UwbConfig List<Integer> uwbConfigs, List<CccPulseShapeCombo> pulseShapeCombos, int ranMultiplier, int maxRangingSessionNumber, int minUwbInitiationTimeMs, @ChapsPerSlot List<Integer> chapsPerSlot, @SyncCodeIndex List<Integer> syncCodes, @Channel List<Integer> channels, @HoppingConfigMode List<Integer> hoppingConfigModes, @HoppingSequence List<Integer> hoppingSequences)72     private CccSpecificationParams(
73             List<CccProtocolVersion> protocolVersions,
74             @UwbConfig List<Integer> uwbConfigs,
75             List<CccPulseShapeCombo> pulseShapeCombos,
76             int ranMultiplier,
77             int maxRangingSessionNumber,
78             int minUwbInitiationTimeMs,
79             @ChapsPerSlot List<Integer> chapsPerSlot,
80             @SyncCodeIndex List<Integer> syncCodes,
81             @Channel List<Integer> channels,
82             @HoppingConfigMode List<Integer> hoppingConfigModes,
83             @HoppingSequence List<Integer> hoppingSequences) {
84         mProtocolVersions = protocolVersions;
85         mUwbConfigs = uwbConfigs;
86         mPulseShapeCombos = pulseShapeCombos;
87         mRanMultiplier = ranMultiplier;
88         mMaxRangingSessionNumber = maxRangingSessionNumber;
89         mMinUwbInitiationTimeMs = minUwbInitiationTimeMs;
90         mChapsPerSlot = chapsPerSlot;
91         mSyncCodes = syncCodes;
92         mChannels = channels;
93         mHoppingConfigModes = hoppingConfigModes;
94         mHoppingSequences = hoppingSequences;
95     }
96 
97     @Override
getBundleVersion()98     protected int getBundleVersion() {
99         return BUNDLE_VERSION_CURRENT;
100     }
101 
102     @Override
toBundle()103     public PersistableBundle toBundle() {
104         PersistableBundle bundle = super.toBundle();
105         String[] protocols = new String[mProtocolVersions.size()];
106         for (int i = 0; i < protocols.length; i++) {
107             protocols[i] = mProtocolVersions.get(i).toString();
108         }
109         String[] pulseShapeCombos = new String[mPulseShapeCombos.size()];
110         for (int i = 0; i < pulseShapeCombos.length; i++) {
111             pulseShapeCombos[i] = mPulseShapeCombos.get(i).toString();
112         }
113         bundle.putStringArray(KEY_PROTOCOL_VERSIONS, protocols);
114         bundle.putIntArray(KEY_UWB_CONFIGS, toIntArray(mUwbConfigs));
115         bundle.putStringArray(KEY_PULSE_SHAPE_COMBOS, pulseShapeCombos);
116         bundle.putInt(KEY_RAN_MULTIPLIER, mRanMultiplier);
117         bundle.putInt(KEY_MAX_RANGING_SESSION_NUMBER, mMaxRangingSessionNumber);
118         bundle.putInt(KEY_MIN_UWB_INITIATION_TIME_MS, mMinUwbInitiationTimeMs);
119         bundle.putIntArray(KEY_CHAPS_PER_SLOTS, toIntArray(mChapsPerSlot));
120         bundle.putIntArray(KEY_SYNC_CODES, toIntArray(mSyncCodes));
121         bundle.putIntArray(KEY_CHANNELS, toIntArray(mChannels));
122         bundle.putIntArray(KEY_HOPPING_CONFIGS, toIntArray(mHoppingConfigModes));
123         bundle.putIntArray(KEY_HOPPING_SEQUENCES, toIntArray(mHoppingSequences));
124         return bundle;
125     }
126 
fromBundle(PersistableBundle bundle)127     public static CccSpecificationParams fromBundle(PersistableBundle bundle) {
128         if (!isCorrectProtocol(bundle)) {
129             throw new IllegalArgumentException("Invalid protocol");
130         }
131 
132         switch (getBundleVersion(bundle)) {
133             case BUNDLE_VERSION_1:
134                 return parseVersion1(bundle);
135 
136             default:
137                 throw new IllegalArgumentException("Invalid bundle version");
138         }
139     }
140 
parseVersion1(PersistableBundle bundle)141     private static CccSpecificationParams parseVersion1(PersistableBundle bundle) {
142         CccSpecificationParams.Builder builder = new CccSpecificationParams.Builder();
143         String[] protocolStrings = checkNotNull(bundle.getStringArray(KEY_PROTOCOL_VERSIONS));
144         for (String protocol : protocolStrings) {
145             builder.addProtocolVersion(CccProtocolVersion.fromString(protocol));
146         }
147 
148         for (int config : checkNotNull(bundle.getIntArray(KEY_UWB_CONFIGS))) {
149             builder.addUwbConfig(config);
150         }
151 
152         String[] pulseShapeComboStrings =
153                 checkNotNull(bundle.getStringArray(KEY_PULSE_SHAPE_COMBOS));
154         for (String pulseShapeCombo : pulseShapeComboStrings) {
155             builder.addPulseShapeCombo(CccPulseShapeCombo.fromString(pulseShapeCombo));
156         }
157 
158         builder.setRanMultiplier(bundle.getInt(KEY_RAN_MULTIPLIER));
159 
160         if (bundle.containsKey(KEY_MAX_RANGING_SESSION_NUMBER)) {
161             builder.setMaxRangingSessionNumber(bundle.getInt(KEY_MAX_RANGING_SESSION_NUMBER));
162         }
163 
164         if (bundle.containsKey(KEY_MIN_UWB_INITIATION_TIME_MS)) {
165             builder.setMinUwbInitiationTimeMs(bundle.getInt(KEY_MIN_UWB_INITIATION_TIME_MS));
166         }
167 
168         for (int chapsPerSlot : checkNotNull(bundle.getIntArray(KEY_CHAPS_PER_SLOTS))) {
169             builder.addChapsPerSlot(chapsPerSlot);
170         }
171 
172         for (int syncCode : checkNotNull(bundle.getIntArray(KEY_SYNC_CODES))) {
173             builder.addSyncCode(syncCode);
174         }
175 
176         for (int channel : checkNotNull(bundle.getIntArray(KEY_CHANNELS))) {
177             builder.addChannel(channel);
178         }
179 
180         for (int hoppingConfig : checkNotNull(bundle.getIntArray(KEY_HOPPING_CONFIGS))) {
181             builder.addHoppingConfigMode(hoppingConfig);
182         }
183 
184         for (int hoppingSequence : checkNotNull(bundle.getIntArray(KEY_HOPPING_SEQUENCES))) {
185             builder.addHoppingSequence(hoppingSequence);
186         }
187 
188         return builder.build();
189     }
190 
toIntArray(List<Integer> data)191     private int[] toIntArray(List<Integer> data) {
192         int[] res = new int[data.size()];
193         for (int i = 0; i < data.size(); i++) {
194             res[i] = data.get(i);
195         }
196         return res;
197     }
198 
getProtocolVersions()199     public List<CccProtocolVersion> getProtocolVersions() {
200         return mProtocolVersions;
201     }
202 
203     @UwbConfig
getUwbConfigs()204     public List<Integer> getUwbConfigs() {
205         return mUwbConfigs;
206     }
207 
getPulseShapeCombos()208     public List<CccPulseShapeCombo> getPulseShapeCombos() {
209         return mPulseShapeCombos;
210     }
211 
212     @IntRange(from = 0, to = 255)
getRanMultiplier()213     public int getRanMultiplier() {
214         return mRanMultiplier;
215     }
216 
getMaxRangingSessionNumber()217     public int getMaxRangingSessionNumber() {
218         return mMaxRangingSessionNumber;
219     }
220 
getMinUwbInitiationTimeMs()221     public int getMinUwbInitiationTimeMs() {
222         return mMinUwbInitiationTimeMs;
223     }
224 
225     @ChapsPerSlot
getChapsPerSlot()226     public List<Integer> getChapsPerSlot() {
227         return mChapsPerSlot;
228     }
229 
230     @SyncCodeIndex
getSyncCodes()231     public List<Integer> getSyncCodes() {
232         return mSyncCodes;
233     }
234 
235     @Channel
getChannels()236     public List<Integer> getChannels() {
237         return mChannels;
238     }
239 
240     @HoppingSequence
getHoppingSequences()241     public List<Integer> getHoppingSequences() {
242         return mHoppingSequences;
243     }
244 
245     @HoppingConfigMode
getHoppingConfigModes()246     public List<Integer> getHoppingConfigModes() {
247         return mHoppingConfigModes;
248     }
249 
250     @Override
equals(@ullable Object other)251     public boolean equals(@Nullable Object other) {
252         if (other instanceof CccSpecificationParams) {
253             CccSpecificationParams otherSpecificationParams = (CccSpecificationParams) other;
254             return otherSpecificationParams.mProtocolVersions.equals(mProtocolVersions)
255                 && otherSpecificationParams.mPulseShapeCombos.equals(mPulseShapeCombos)
256                 && otherSpecificationParams.mUwbConfigs.equals(mUwbConfigs)
257                 && otherSpecificationParams.mRanMultiplier == mRanMultiplier
258                 && otherSpecificationParams.mMaxRangingSessionNumber == mMaxRangingSessionNumber
259                 && otherSpecificationParams.mMinUwbInitiationTimeMs == mMinUwbInitiationTimeMs
260                 && otherSpecificationParams.mChapsPerSlot.equals(mChapsPerSlot)
261                 && otherSpecificationParams.mSyncCodes.equals(mSyncCodes)
262                 && otherSpecificationParams.mChannels.equals(mChannels)
263                 && otherSpecificationParams.mHoppingConfigModes.equals(mHoppingConfigModes)
264                 && otherSpecificationParams.mHoppingSequences.equals(mHoppingSequences);
265         }
266         return false;
267     }
268 
269     @Override
hashCode()270     public int hashCode() {
271         return Arrays.hashCode(
272             new int[] {
273                 mProtocolVersions.hashCode(),
274                 mPulseShapeCombos.hashCode(),
275                 mUwbConfigs.hashCode(),
276                 mRanMultiplier,
277                 mMaxRangingSessionNumber,
278                 mMinUwbInitiationTimeMs,
279                 mChapsPerSlot.hashCode(),
280                 mSyncCodes.hashCode(),
281                 mChannels.hashCode(),
282                 mHoppingConfigModes.hashCode(),
283                 mHoppingSequences.hashCode()
284             });
285     }
286 
287     /** Builder */
288     public static class Builder {
289         private List<CccProtocolVersion> mProtocolVersions = new ArrayList<>();
290         @UwbConfig private List<Integer> mUwbConfigs = new ArrayList<>();
291         private List<CccPulseShapeCombo> mPulseShapeCombos = new ArrayList<>();
292         private RequiredParam<Integer> mRanMultiplier = new RequiredParam<>();
293         private int mMinUwbInitiationTimeMs = -1;
294         private int mMaxRangingSessionNumber = DEFAULT_MAX_RANGING_SESSIONS_NUMBER;
295         @ChapsPerSlot private List<Integer> mChapsPerSlot = new ArrayList<>();
296         @SyncCodeIndex private List<Integer> mSyncCodes = new ArrayList<>();
297         @Channel private List<Integer> mChannels = new ArrayList<>();
298         @HoppingSequence private List<Integer> mHoppingSequences = new ArrayList<>();
299         @HoppingConfigMode private List<Integer> mHoppingConfigModes = new ArrayList<>();
300 
addProtocolVersion(@onNull CccProtocolVersion version)301         public Builder addProtocolVersion(@NonNull CccProtocolVersion version) {
302             mProtocolVersions.add(version);
303             return this;
304         }
305 
addUwbConfig(@wbConfig int uwbConfig)306         public Builder addUwbConfig(@UwbConfig int uwbConfig) {
307             mUwbConfigs.add(uwbConfig);
308             return this;
309         }
310 
addPulseShapeCombo(CccPulseShapeCombo pulseShapeCombo)311         public Builder addPulseShapeCombo(CccPulseShapeCombo pulseShapeCombo) {
312             mPulseShapeCombos.add(pulseShapeCombo);
313             return this;
314         }
315 
setRanMultiplier(int ranMultiplier)316         public Builder setRanMultiplier(int ranMultiplier) {
317             if (ranMultiplier < 0 || ranMultiplier > 255) {
318                 throw new IllegalArgumentException("Invalid RAN Multiplier");
319             }
320             mRanMultiplier.set(ranMultiplier);
321             return this;
322         }
323 
324         /**
325          * Set maximum supported ranging session number
326          * @param maxRangingSessionNumber : maximum ranging session number supported
327          * @return CccSpecificationParams builder
328          */
setMaxRangingSessionNumber(int maxRangingSessionNumber)329         public Builder setMaxRangingSessionNumber(int maxRangingSessionNumber) {
330             mMaxRangingSessionNumber = maxRangingSessionNumber;
331             return this;
332         }
333 
334         /**
335          * Set minimum initiation time delay in ms
336          * @param minUwbInitiationTimeMs : minimum initiation time delay supported
337          * @return CccSpecificationParams builder
338          */
setMinUwbInitiationTimeMs(int minUwbInitiationTimeMs)339         public Builder setMinUwbInitiationTimeMs(int minUwbInitiationTimeMs) {
340             mMinUwbInitiationTimeMs = minUwbInitiationTimeMs;
341             return this;
342         }
343 
addChapsPerSlot(@hapsPerSlot int chapsPerSlot)344         public Builder addChapsPerSlot(@ChapsPerSlot int chapsPerSlot) {
345             mChapsPerSlot.add(chapsPerSlot);
346             return this;
347         }
348 
addSyncCode(@yncCodeIndex int syncCode)349         public Builder addSyncCode(@SyncCodeIndex int syncCode) {
350             mSyncCodes.add(syncCode);
351             return this;
352         }
353 
addChannel(@hannel int channel)354         public Builder addChannel(@Channel int channel) {
355             mChannels.add(channel);
356             return this;
357         }
358 
addHoppingConfigMode(@oppingConfigMode int hoppingConfigMode)359         public Builder addHoppingConfigMode(@HoppingConfigMode int hoppingConfigMode) {
360             mHoppingConfigModes.add(hoppingConfigMode);
361             return this;
362         }
363 
addHoppingSequence(@oppingSequence int hoppingSequence)364         public Builder addHoppingSequence(@HoppingSequence int hoppingSequence) {
365             mHoppingSequences.add(hoppingSequence);
366             return this;
367         }
368 
build()369         public CccSpecificationParams build() {
370             if (mProtocolVersions.size() == 0) {
371                 throw new IllegalStateException("No protocol versions set");
372             }
373 
374             if (mUwbConfigs.size() == 0) {
375                 throw new IllegalStateException("No UWB Configs set");
376             }
377 
378             if (mPulseShapeCombos.size() == 0) {
379                 throw new IllegalStateException("No Pulse Shape Combos set");
380             }
381 
382             if (mChapsPerSlot.size() == 0) {
383                 throw new IllegalStateException("No Slot Durations set");
384             }
385 
386             if (mSyncCodes.size() == 0) {
387                 throw new IllegalStateException("No Sync Codes set");
388             }
389 
390             if (mHoppingConfigModes.size() == 0) {
391                 throw new IllegalStateException("No hopping config modes set");
392             }
393 
394             if (mHoppingSequences.size() == 0) {
395                 throw new IllegalStateException("No hopping sequences set");
396             }
397 
398             return new CccSpecificationParams(
399                     mProtocolVersions,
400                     mUwbConfigs,
401                     mPulseShapeCombos,
402                     mRanMultiplier.get(),
403                     mMaxRangingSessionNumber,
404                     mMinUwbInitiationTimeMs,
405                     mChapsPerSlot,
406                     mSyncCodes,
407                     mChannels,
408                     mHoppingConfigModes,
409                     mHoppingSequences);
410         }
411     }
412 }
413