1 /*
2  * Copyright 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.ranging.uwb;
18 
19 import static com.google.common.collect.ImmutableList.toImmutableList;
20 
21 import android.ranging.uwb.UwbAddress;
22 
23 import com.android.server.ranging.RangingTechnology;
24 import com.android.server.ranging.RangingUtils.Conversions;
25 import com.android.server.ranging.oob.TechnologyHeader;
26 
27 import com.google.auto.value.AutoValue;
28 import com.google.common.collect.ImmutableList;
29 
30 import java.nio.ByteBuffer;
31 import java.util.Arrays;
32 
33 /** Capability data for UWB sent as part of CapabilityResponseMessage. */
34 @AutoValue
35 public abstract class UwbOobCapabilities {
36 
37     /** Size in bytes of all properties when serialized. */
38     private static final int EXPECTED_SIZE_BYTES = 20;
39 
40     // Size in bytes for each properties for serialization/deserialization.
41     private static final int UWB_ADDRESS_SIZE = 2;
42     private static final int CHANNELS_SIZE = 4;
43     private static final int PREAMBLES_SIZE = 4;
44     private static final int CONFIG_IDS_SIZE = 4;
45     private static final int MIN_INTERVAL_SIZE = 2;
46     private static final int MIN_SLOT_SIZE = 1;
47     private static final int DEVICE_ROLE_SIZE = 1;
48 
49     private static final int CHANNELS_SHIFT = 0;
50     private static final int PREAMBLES_SHIFT = 1;
51     private static final int CONFIG_IDS_SHIFT = 0;
52     private static final int DEVICE_ROLE_SHIFT = 1;
53 
54     /** Returns the size of the object in bytes when serialized. */
getSize()55     public static int getSize() {
56         return EXPECTED_SIZE_BYTES;
57     }
58 
59     /**
60      * Parses the given byte array and returns {@link UwbOobCapabilities} object. Throws {@link
61      * IllegalArgumentException} on invalid input.
62      */
parseBytes(byte[] capabilitiesBytes)63     public static UwbOobCapabilities parseBytes(byte[] capabilitiesBytes) {
64         TechnologyHeader header = TechnologyHeader.parseBytes(capabilitiesBytes);
65 
66         if (capabilitiesBytes.length < EXPECTED_SIZE_BYTES) {
67             throw new IllegalArgumentException(
68                     String.format(
69                             "UwbCapabilities size is %d, expected at least %d",
70                             capabilitiesBytes.length, EXPECTED_SIZE_BYTES));
71         }
72 
73         if (capabilitiesBytes.length < header.getSize()) {
74             throw new IllegalArgumentException(
75                     String.format(
76                             "UwbCapabilities header size field is %d, but the size of the array "
77                                     + "is %d",
78                             header.getSize(), capabilitiesBytes.length));
79         }
80 
81         if (header.getRangingTechnology() != RangingTechnology.UWB) {
82             throw new IllegalArgumentException(
83                     String.format(
84                             "UwbCapabilities header technology field is %s, expected %s",
85                             header.getRangingTechnology(), RangingTechnology.UWB));
86         }
87 
88         int parseCursor = header.getHeaderSize();
89 
90         // Parse UWB Address
91         UwbAddress uwbAddress =
92                 UwbAddress.fromBytes(
93                         Arrays.copyOfRange(capabilitiesBytes, parseCursor,
94                                 parseCursor + UWB_ADDRESS_SIZE));
95         parseCursor += UWB_ADDRESS_SIZE;
96 
97         // Parse Supported Channels
98         ImmutableList<Integer> supportedChannels =
99                 Conversions.byteArrayToIntList(
100                         Arrays.copyOfRange(capabilitiesBytes, parseCursor,
101                                 parseCursor + CHANNELS_SIZE),
102                         CHANNELS_SHIFT);
103         parseCursor += CHANNELS_SIZE;
104 
105         // Parse Supported Preamble Indexes
106         ImmutableList<Integer> supportedPreambleIndexes =
107                 Conversions.byteArrayToIntList(
108                         Arrays.copyOfRange(capabilitiesBytes, parseCursor,
109                                 parseCursor + PREAMBLES_SIZE),
110                         PREAMBLES_SHIFT);
111         parseCursor += PREAMBLES_SIZE;
112 
113         // Parse Supported Config Ids
114         ImmutableList<Integer> supportedConfigIds =
115                 Conversions.byteArrayToIntList(
116                         Arrays.copyOfRange(capabilitiesBytes, parseCursor,
117                                 parseCursor + CONFIG_IDS_SIZE),
118                         CONFIG_IDS_SHIFT);
119         parseCursor += CONFIG_IDS_SIZE;
120 
121         // Parse Minimum Ranging Interval Ms
122         int minimumRangingIntervalMs =
123                 Conversions.byteArrayToInt(
124                         Arrays.copyOfRange(capabilitiesBytes, parseCursor,
125                                 parseCursor + MIN_INTERVAL_SIZE));
126         parseCursor += MIN_INTERVAL_SIZE;
127 
128         // Parse Minimum Slot Duration Ms
129         int minimumSlotDurationMs =
130                 Conversions.byteArrayToInt(
131                         Arrays.copyOfRange(capabilitiesBytes, parseCursor,
132                                 parseCursor + MIN_SLOT_SIZE));
133         parseCursor += MIN_SLOT_SIZE;
134 
135         // Parse Device Role
136         ImmutableList<Integer> deviceRoles =
137                 Conversions.byteArrayToIntList(
138                                 Arrays.copyOfRange(capabilitiesBytes, parseCursor,
139                                         parseCursor + DEVICE_ROLE_SIZE),
140                                 DEVICE_ROLE_SHIFT)
141                         .stream()
142                         .collect(toImmutableList());
143         parseCursor += DEVICE_ROLE_SIZE;
144 
145         return UwbOobCapabilities.builder()
146                 .setUwbAddress(uwbAddress)
147                 .setSupportedChannels(supportedChannels)
148                 .setSupportedConfigIds(supportedConfigIds)
149                 .setSupportedPreambleIndexes(supportedPreambleIndexes)
150                 .setMinimumRangingIntervalMs(minimumRangingIntervalMs)
151                 .setMinimumSlotDurationMs(minimumSlotDurationMs)
152                 .setSupportedDeviceRole(deviceRoles)
153                 .build();
154     }
155 
156     /** Serializes this {@link UwbOobCapabilities} object to bytes. */
toBytes()157     public final byte[] toBytes() {
158         ByteBuffer byteBuffer = ByteBuffer.allocate(EXPECTED_SIZE_BYTES);
159         byteBuffer
160                 .put(RangingTechnology.UWB.toByte())
161                 .put((byte) EXPECTED_SIZE_BYTES)
162                 .put(getUwbAddress().getAddressBytes())
163                 .put(Conversions.intListToByteArrayBitmap(getSupportedChannels(), CHANNELS_SIZE,
164                         CHANNELS_SHIFT))
165                 .put(
166                         Conversions.intListToByteArrayBitmap(
167                                 getSupportedPreambleIndexes(), PREAMBLES_SIZE, PREAMBLES_SHIFT))
168                 .put(
169                         Conversions.intListToByteArrayBitmap(
170                                 getSupportedConfigIds(), CONFIG_IDS_SIZE, CONFIG_IDS_SHIFT))
171                 .put(Conversions.intToByteArray(getMinimumRangingIntervalMs(), MIN_INTERVAL_SIZE))
172                 .put(Conversions.intToByteArray(getMinimumSlotDurationMs(), MIN_SLOT_SIZE))
173                 .put(
174                         Conversions.intListToByteArrayBitmap(
175                                 getSupportedDeviceRole().stream()
176                                         .collect(toImmutableList()),
177                                 DEVICE_ROLE_SIZE,
178                                 DEVICE_ROLE_SHIFT));
179 
180         return byteBuffer.array();
181     }
182 
183     /** Returns the {@link UwbAddress} of the device. */
getUwbAddress()184     public abstract UwbAddress getUwbAddress();
185 
186     /** Returns a list of supported channels. */
getSupportedChannels()187     public abstract ImmutableList<Integer> getSupportedChannels();
188 
189     /** Returns a list of supported preamble indexes. */
getSupportedPreambleIndexes()190     public abstract ImmutableList<Integer> getSupportedPreambleIndexes();
191 
192     /** Returns a list of supported config Ids. */
getSupportedConfigIds()193     public abstract ImmutableList<Integer> getSupportedConfigIds();
194 
195     /** Returns minimum supported ranging interval in ms. */
getMinimumRangingIntervalMs()196     public abstract int getMinimumRangingIntervalMs();
197 
198     /** Returns minimum supported slot duration in ms. */
getMinimumSlotDurationMs()199     public abstract int getMinimumSlotDurationMs();
200 
201     /** Returns supported device roles. */
getSupportedDeviceRole()202     public abstract ImmutableList<Integer> getSupportedDeviceRole();
203 
204     /** Returns a builder for {@link UwbOobCapabilities}. */
builder()205     public static Builder builder() {
206         return new AutoValue_UwbOobCapabilities.Builder();
207     }
208 
209     /** Builder for {@link UwbOobCapabilities}. */
210     @AutoValue.Builder
211     public abstract static class Builder {
212 
setUwbAddress(UwbAddress uwbAddress)213         public abstract Builder setUwbAddress(UwbAddress uwbAddress);
214 
setSupportedChannels(ImmutableList<Integer> supportedChannels)215         public abstract Builder setSupportedChannels(ImmutableList<Integer> supportedChannels);
216 
setSupportedPreambleIndexes( ImmutableList<Integer> supportedPreambleIndexes)217         public abstract Builder setSupportedPreambleIndexes(
218                 ImmutableList<Integer> supportedPreambleIndexes);
219 
setSupportedConfigIds(ImmutableList<Integer> supportedConfigIds)220         public abstract Builder setSupportedConfigIds(ImmutableList<Integer> supportedConfigIds);
221 
setMinimumRangingIntervalMs(int minimumRangingIntervalMs)222         public abstract Builder setMinimumRangingIntervalMs(int minimumRangingIntervalMs);
223 
setMinimumSlotDurationMs(int minimumSlotDurationMs)224         public abstract Builder setMinimumSlotDurationMs(int minimumSlotDurationMs);
225 
setSupportedDeviceRole( ImmutableList<Integer> supportedDeviceRole)226         public abstract Builder setSupportedDeviceRole(
227                 ImmutableList<Integer> supportedDeviceRole);
228 
build()229         public abstract UwbOobCapabilities build();
230     }
231 }
232