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