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;
18 
19 import static org.junit.Assert.assertArrayEquals;
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertTrue;
22 
23 import android.os.PersistableBundle;
24 
25 import androidx.test.ext.junit.runners.AndroidJUnit4;
26 import androidx.test.filters.SmallTest;
27 
28 import com.google.uwb.support.base.Params;
29 import com.google.uwb.support.ccc.CccOpenRangingParams;
30 import com.google.uwb.support.ccc.CccParams;
31 import com.google.uwb.support.ccc.CccProtocolVersion;
32 import com.google.uwb.support.ccc.CccPulseShapeCombo;
33 import com.google.uwb.support.ccc.CccRangingError;
34 import com.google.uwb.support.ccc.CccRangingReconfiguredParams;
35 import com.google.uwb.support.ccc.CccRangingStartedParams;
36 import com.google.uwb.support.ccc.CccSpecificationParams;
37 import com.google.uwb.support.ccc.CccStartRangingParams;
38 
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 
42 import java.util.List;
43 
44 @SmallTest
45 @RunWith(AndroidJUnit4.class)
46 public class CccTests {
47     private static final CccProtocolVersion[] PROTOCOL_VERSIONS =
48             new CccProtocolVersion[] {
49                     new CccProtocolVersion(1, 0),
50                     new CccProtocolVersion(2, 0),
51                     new CccProtocolVersion(2, 1)
52             };
53 
54     private static final  Integer[] UWB_CONFIGS =
55             new Integer[] {CccParams.UWB_CONFIG_0, CccParams.UWB_CONFIG_1};
56     private static final CccPulseShapeCombo[] PULSE_SHAPE_COMBOS =
57             new CccPulseShapeCombo[] {
58                     new CccPulseShapeCombo(
59                             CccParams.PULSE_SHAPE_SYMMETRICAL_ROOT_RAISED_COSINE,
60                             CccParams.PULSE_SHAPE_SYMMETRICAL_ROOT_RAISED_COSINE),
61                     new CccPulseShapeCombo(
62                             CccParams.PULSE_SHAPE_PRECURSOR_FREE,
63                             CccParams.PULSE_SHAPE_PRECURSOR_FREE),
64                     new CccPulseShapeCombo(
65                             CccParams.PULSE_SHAPE_PRECURSOR_FREE_SPECIAL,
66                             CccParams.PULSE_SHAPE_PRECURSOR_FREE_SPECIAL)
67             };
68     private static final int RAN_MULTIPLIER = 200;
69     private static final Integer[] CHAPS_PER_SLOTS =
70             new Integer[] {CccParams.CHAPS_PER_SLOT_4, CccParams.CHAPS_PER_SLOT_12};
71     private static final Integer[] SYNC_CODES = new Integer[] {10, 23};
72     private static final Integer[] CHANNELS =
73             new Integer[] {CccParams.UWB_CHANNEL_5, CccParams.UWB_CHANNEL_9};
74     private static final Integer[] HOPPING_CONFIG_MODES =
75             new Integer[] {
76                     CccParams.HOPPING_CONFIG_MODE_ADAPTIVE, CccParams.HOPPING_CONFIG_MODE_CONTINUOUS
77             };
78     private static final Integer[] HOPPING_SEQUENCES =
79             new Integer[] {CccParams.HOPPING_SEQUENCE_AES, CccParams.HOPPING_SEQUENCE_DEFAULT};
80 
81     @Test
testOpenRangingParams()82     public void testOpenRangingParams() {
83         CccProtocolVersion protocolVersion = CccParams.PROTOCOL_VERSION_1_0;
84         @CccParams.UwbConfig int uwbConfig = CccParams.UWB_CONFIG_1;
85         CccPulseShapeCombo pulseShapeCombo =
86                 new CccPulseShapeCombo(
87                         CccParams.PULSE_SHAPE_PRECURSOR_FREE, CccParams.PULSE_SHAPE_PRECURSOR_FREE);
88         int sessionId = 10;
89         int ranMultiplier = 128;
90         @CccParams.Channel int channel = CccParams.UWB_CHANNEL_9;
91         @CccParams.ChapsPerSlot int chapsPerSlot = CccParams.CHAPS_PER_SLOT_6;
92         int numResponderNodes = 9;
93         @CccParams.SlotsPerRound int numSlotsPerRound = CccParams.SLOTS_PER_ROUND_12;
94         @CccParams.SyncCodeIndex int syncCodeIdx = 22;
95         @CccParams.HoppingConfigMode int hoppingConfigMode = CccParams.HOPPING_CONFIG_MODE_ADAPTIVE;
96         @CccParams.HoppingSequence int hoppingSequence = CccParams.HOPPING_SEQUENCE_AES;
97         long absoluteInitiationTimeUs = 20_000L;
98         int rangeDataNtfConfig = CccParams.RANGE_DATA_NTF_CONFIG_ENABLE;
99         int rangeDataNtfProximityNear = 100;
100         int rangeDataNtfProximityFar = 200;
101         double rangeDataNtfAoaAzimuthLower = -0.7;
102         double rangeDataNtfAoaAzimuthUpper = +1.3;
103         double rangeDataNtfAoaElevationLower = -1.1;
104         double rangeDataNtfAoaElevationUpper = +1.2;
105 
106         CccOpenRangingParams params =
107                 new CccOpenRangingParams.Builder()
108                         .setProtocolVersion(protocolVersion)
109                         .setUwbConfig(uwbConfig)
110                         .setPulseShapeCombo(pulseShapeCombo)
111                         .setSessionId(sessionId)
112                         .setRanMultiplier(ranMultiplier)
113                         .setChannel(channel)
114                         .setNumChapsPerSlot(chapsPerSlot)
115                         .setNumResponderNodes(numResponderNodes)
116                         .setNumSlotsPerRound(numSlotsPerRound)
117                         .setSyncCodeIndex(syncCodeIdx)
118                         .setHoppingConfigMode(hoppingConfigMode)
119                         .setHoppingSequence(hoppingSequence)
120                         .setAbsoluteInitiationTimeUs(absoluteInitiationTimeUs)
121                         .setRangeDataNtfConfig(rangeDataNtfConfig)
122                         .setRangeDataNtfProximityNear(rangeDataNtfProximityNear)
123                         .setRangeDataNtfProximityFar(rangeDataNtfProximityFar)
124                         .setRangeDataNtfAoaAzimuthLower(rangeDataNtfAoaAzimuthLower)
125                         .setRangeDataNtfAoaAzimuthUpper(rangeDataNtfAoaAzimuthUpper)
126                         .setRangeDataNtfAoaElevationLower(rangeDataNtfAoaElevationLower)
127                         .setRangeDataNtfAoaElevationUpper(rangeDataNtfAoaElevationUpper)
128                         .build();
129 
130         assertEquals(params.getProtocolVersion(), protocolVersion);
131         assertEquals(params.getUwbConfig(), uwbConfig);
132         assertEquals(
133                 params.getPulseShapeCombo().getInitiatorTx(), pulseShapeCombo.getInitiatorTx());
134         assertEquals(
135                 params.getPulseShapeCombo().getResponderTx(), pulseShapeCombo.getResponderTx());
136         assertEquals(params.getSessionId(), sessionId);
137         assertEquals(params.getSessionType(), CccParams.SESSION_TYPE_CCC);
138         assertEquals(params.getRanMultiplier(), ranMultiplier);
139         assertEquals(params.getChannel(), channel);
140         assertEquals(params.getNumChapsPerSlot(), chapsPerSlot);
141         assertEquals(params.getNumResponderNodes(), numResponderNodes);
142         assertEquals(params.getNumSlotsPerRound(), numSlotsPerRound);
143         assertEquals(params.getSyncCodeIndex(), syncCodeIdx);
144         assertEquals(params.getHoppingConfigMode(), hoppingConfigMode);
145         assertEquals(params.getHoppingSequence(), hoppingSequence);
146         assertEquals(params.getAbsoluteInitiationTimeUs(), absoluteInitiationTimeUs);
147 
148         CccOpenRangingParams fromBundle = CccOpenRangingParams.fromBundle(params.toBundle());
149         assertEquals(fromBundle.getProtocolVersion(), protocolVersion);
150         assertEquals(fromBundle.getUwbConfig(), uwbConfig);
151         assertEquals(
152                 fromBundle.getPulseShapeCombo().getInitiatorTx(), pulseShapeCombo.getInitiatorTx());
153         assertEquals(
154                 fromBundle.getPulseShapeCombo().getResponderTx(), pulseShapeCombo.getResponderTx());
155         assertEquals(fromBundle.getSessionId(), sessionId);
156         assertEquals(fromBundle.getRanMultiplier(), ranMultiplier);
157         assertEquals(fromBundle.getChannel(), channel);
158         assertEquals(fromBundle.getNumChapsPerSlot(), chapsPerSlot);
159         assertEquals(fromBundle.getNumResponderNodes(), numResponderNodes);
160         assertEquals(fromBundle.getNumSlotsPerRound(), numSlotsPerRound);
161         assertEquals(fromBundle.getSyncCodeIndex(), syncCodeIdx);
162         assertEquals(fromBundle.getHoppingConfigMode(), hoppingConfigMode);
163         assertEquals(fromBundle.getHoppingSequence(), hoppingSequence);
164         assertEquals(fromBundle.getAbsoluteInitiationTimeUs(), absoluteInitiationTimeUs);
165         assertEquals(fromBundle.getRangeDataNtfConfig(), rangeDataNtfConfig);
166         assertEquals(fromBundle.getRangeDataNtfProximityNear(), rangeDataNtfProximityNear);
167         assertEquals(fromBundle.getRangeDataNtfProximityFar(), rangeDataNtfProximityFar);
168         assertEquals(
169                 fromBundle.getRangeDataNtfAoaAzimuthLower(), rangeDataNtfAoaAzimuthLower, 0.1d);
170         assertEquals(
171                 fromBundle.getRangeDataNtfAoaAzimuthUpper(), rangeDataNtfAoaAzimuthUpper, 0.1d);
172         assertEquals(
173                 fromBundle.getRangeDataNtfAoaElevationLower(), rangeDataNtfAoaElevationLower, 0.1d);
174         assertEquals(
175                 fromBundle.getRangeDataNtfAoaElevationUpper(), rangeDataNtfAoaElevationUpper, 0.1d);
176 
177         verifyProtocolPresent(params);
178         verifyBundlesEqual(params, fromBundle);
179     }
180 
181     @Test
testRangingError()182     public void testRangingError() {
183         @CccParams.ProtocolError int error = CccParams.PROTOCOL_ERROR_SE_BUSY;
184         CccRangingError params = new CccRangingError.Builder().setError(error).build();
185 
186         assertEquals(params.getError(), error);
187 
188         CccRangingError fromBundle = CccRangingError.fromBundle(params.toBundle());
189         assertEquals(fromBundle.getError(), error);
190 
191         verifyProtocolPresent(params);
192         verifyBundlesEqual(params, fromBundle);
193     }
194 
195     @Test
testRangingReconfiguredParams()196     public void testRangingReconfiguredParams() {
197         CccRangingReconfiguredParams params = new CccRangingReconfiguredParams.Builder().build();
198 
199         CccRangingReconfiguredParams fromBundle =
200                 CccRangingReconfiguredParams.fromBundle(params.toBundle());
201 
202         verifyProtocolPresent(params);
203         verifyBundlesEqual(params, fromBundle);
204     }
205 
206     @Test
testStartRangingParams()207     public void testStartRangingParams() {
208         int sessionId = 10;
209         int ranMultiplier = 128;
210         long initiationTimeMs = 10;
211         long absoluteInitiationTimeUs = 15_000L;
212 
213         CccStartRangingParams params =
214                 new CccStartRangingParams.Builder()
215                         .setSessionId(sessionId)
216                         .setRanMultiplier(ranMultiplier)
217                         .setInitiationTimeMs(initiationTimeMs)
218                         .setAbsoluteInitiationTimeUs(absoluteInitiationTimeUs)
219                         .build();
220 
221         assertEquals(params.getSessionId(), sessionId);
222         assertEquals(params.getRanMultiplier(), ranMultiplier);
223         assertEquals(params.getInitiationTimeMs(), initiationTimeMs);
224         assertEquals(params.getAbsoluteInitiationTimeUs(), absoluteInitiationTimeUs);
225 
226         CccStartRangingParams fromBundle = CccStartRangingParams.fromBundle(params.toBundle());
227 
228         assertEquals(fromBundle.getSessionId(), sessionId);
229         assertEquals(fromBundle.getRanMultiplier(), ranMultiplier);
230         assertEquals(fromBundle.getInitiationTimeMs(), initiationTimeMs);
231         assertEquals(fromBundle.getAbsoluteInitiationTimeUs(), absoluteInitiationTimeUs);
232 
233         verifyProtocolPresent(params);
234         verifyBundlesEqual(params, fromBundle);
235     }
236 
237     @Test
testRangingStartedParams()238     public void testRangingStartedParams() {
239         int hopModeKey = 98876444;
240         int startingStsIndex = 246802468;
241         @CccParams.SyncCodeIndex int syncCodeIndex = 10;
242         long uwbTime0 = 50;
243         int ranMultiplier = 10;
244 
245         CccRangingStartedParams params =
246                 new CccRangingStartedParams.Builder()
247                         .setHopModeKey(hopModeKey)
248                         .setStartingStsIndex(startingStsIndex)
249                         .setSyncCodeIndex(syncCodeIndex)
250                         .setUwbTime0(uwbTime0)
251                         .setRanMultiplier(ranMultiplier)
252                         .build();
253 
254         assertEquals(params.getHopModeKey(), hopModeKey);
255         assertEquals(params.getStartingStsIndex(), startingStsIndex);
256         assertEquals(params.getSyncCodeIndex(), syncCodeIndex);
257         assertEquals(params.getUwbTime0(), uwbTime0);
258         assertEquals(params.getRanMultiplier(), ranMultiplier);
259 
260         CccRangingStartedParams fromBundle = CccRangingStartedParams.fromBundle(params.toBundle());
261 
262         assertEquals(fromBundle.getHopModeKey(), hopModeKey);
263         assertEquals(fromBundle.getStartingStsIndex(), startingStsIndex);
264         assertEquals(fromBundle.getSyncCodeIndex(), syncCodeIndex);
265         assertEquals(fromBundle.getUwbTime0(), uwbTime0);
266         assertEquals(fromBundle.getRanMultiplier(), ranMultiplier);
267 
268         verifyProtocolPresent(params);
269         verifyBundlesEqual(params, fromBundle);
270     }
271 
272     @Test
testSpecificationParams()273     public void testSpecificationParams() {
274         CccSpecificationParams.Builder paramsBuilder = new CccSpecificationParams.Builder();
275         for (CccProtocolVersion p : PROTOCOL_VERSIONS) {
276             paramsBuilder.addProtocolVersion(p);
277         }
278 
279         for (int uwbConfig : UWB_CONFIGS) {
280             paramsBuilder.addUwbConfig(uwbConfig);
281         }
282 
283         for (CccPulseShapeCombo pulseShapeCombo : PULSE_SHAPE_COMBOS) {
284             paramsBuilder.addPulseShapeCombo(pulseShapeCombo);
285         }
286 
287         paramsBuilder.setRanMultiplier(RAN_MULTIPLIER);
288 
289         for (int chapsPerSlot : CHAPS_PER_SLOTS) {
290             paramsBuilder.addChapsPerSlot(chapsPerSlot);
291         }
292 
293         for (int syncCode : SYNC_CODES) {
294             paramsBuilder.addSyncCode(syncCode);
295         }
296 
297         for (int channel : CHANNELS) {
298             paramsBuilder.addChannel(channel);
299         }
300 
301         for (int hoppingConfigMode : HOPPING_CONFIG_MODES) {
302             paramsBuilder.addHoppingConfigMode(hoppingConfigMode);
303         }
304 
305         for (int hoppingSequence : HOPPING_SEQUENCES) {
306             paramsBuilder.addHoppingSequence(hoppingSequence);
307         }
308 
309         CccSpecificationParams params = paramsBuilder.build();
310         assertArrayEquals(params.getProtocolVersions().toArray(), PROTOCOL_VERSIONS);
311         assertArrayEquals(params.getUwbConfigs().toArray(), UWB_CONFIGS);
312         assertArrayEquals(params.getPulseShapeCombos().toArray(), PULSE_SHAPE_COMBOS);
313         assertEquals(params.getRanMultiplier(), RAN_MULTIPLIER);
314         assertArrayEquals(params.getChapsPerSlot().toArray(), CHAPS_PER_SLOTS);
315         assertArrayEquals(params.getSyncCodes().toArray(), SYNC_CODES);
316         assertArrayEquals(params.getChannels().toArray(), CHANNELS);
317         assertArrayEquals(params.getHoppingConfigModes().toArray(), HOPPING_CONFIG_MODES);
318         assertArrayEquals(params.getHoppingSequences().toArray(), HOPPING_SEQUENCES);
319 
320         CccSpecificationParams fromBundle = CccSpecificationParams.fromBundle(params.toBundle());
321         assertArrayEquals(fromBundle.getProtocolVersions().toArray(), PROTOCOL_VERSIONS);
322         assertArrayEquals(fromBundle.getUwbConfigs().toArray(), UWB_CONFIGS);
323         assertArrayEquals(fromBundle.getPulseShapeCombos().toArray(), PULSE_SHAPE_COMBOS);
324         assertEquals(fromBundle.getRanMultiplier(), RAN_MULTIPLIER);
325         assertArrayEquals(fromBundle.getChapsPerSlot().toArray(), CHAPS_PER_SLOTS);
326         assertArrayEquals(fromBundle.getSyncCodes().toArray(), SYNC_CODES);
327         assertArrayEquals(fromBundle.getChannels().toArray(), CHANNELS);
328         assertArrayEquals(fromBundle.getHoppingConfigModes().toArray(), HOPPING_CONFIG_MODES);
329         assertArrayEquals(fromBundle.getHoppingSequences().toArray(), HOPPING_SEQUENCES);
330 
331         verifyProtocolPresent(params);
332         assertTrue(params.equals(fromBundle));
333 
334         // Add random channel to params builder to force inequality.
335         paramsBuilder.addChannel(0);
336         // Rebuild params.
337         params = paramsBuilder.build();
338         // Test that params and fromBundle are not equal.
339         assertTrue(!params.equals(fromBundle));
340     }
341 
342     @Test
testSpecificationParams_whenNoChannelsSet()343     public void testSpecificationParams_whenNoChannelsSet() {
344         CccSpecificationParams.Builder paramsBuilder = new CccSpecificationParams.Builder();
345         for (CccProtocolVersion p : PROTOCOL_VERSIONS) {
346             paramsBuilder.addProtocolVersion(p);
347         }
348         for (int uwbConfig : UWB_CONFIGS) {
349             paramsBuilder.addUwbConfig(uwbConfig);
350         }
351         for (CccPulseShapeCombo pulseShapeCombo : PULSE_SHAPE_COMBOS) {
352             paramsBuilder.addPulseShapeCombo(pulseShapeCombo);
353         }
354         paramsBuilder.setRanMultiplier(RAN_MULTIPLIER);
355         for (int chapsPerSlot : CHAPS_PER_SLOTS) {
356             paramsBuilder.addChapsPerSlot(chapsPerSlot);
357         }
358         for (int syncCode : SYNC_CODES) {
359             paramsBuilder.addSyncCode(syncCode);
360         }
361         for (int hoppingConfigMode : HOPPING_CONFIG_MODES) {
362             paramsBuilder.addHoppingConfigMode(hoppingConfigMode);
363         }
364         for (int hoppingSequence : HOPPING_SEQUENCES) {
365             paramsBuilder.addHoppingSequence(hoppingSequence);
366         }
367         CccSpecificationParams params = paramsBuilder.build();
368         assertEquals(List.of(), params.getChannels());
369 
370         CccSpecificationParams fromBundle = CccSpecificationParams.fromBundle(params.toBundle());
371         assertEquals(List.of(), fromBundle.getChannels());
372     }
373 
verifyProtocolPresent(Params params)374     private void verifyProtocolPresent(Params params) {
375         assertTrue(Params.isProtocol(params.toBundle(), CccParams.PROTOCOL_NAME));
376     }
377 
verifyBundlesEqual(Params params, Params fromBundle)378     private void verifyBundlesEqual(Params params, Params fromBundle) {
379         assertTrue(PersistableBundle.kindofEquals(params.toBundle(), fromBundle.toBundle()));
380     }
381 }
382