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 android.ranging.uwb; 18 19 import static android.ranging.raw.RawRangingDevice.UPDATE_RATE_NORMAL; 20 21 import android.annotation.FlaggedApi; 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 import android.ranging.raw.RawRangingDevice.RangingUpdateRate; 28 29 import com.android.ranging.flags.Flags; 30 31 import java.lang.annotation.ElementType; 32 import java.lang.annotation.Retention; 33 import java.lang.annotation.RetentionPolicy; 34 import java.lang.annotation.Target; 35 import java.util.Arrays; 36 import java.util.Objects; 37 38 /** 39 * UwbRangingParams encapsulates the parameters required for a UWB ranging session. 40 */ 41 @FlaggedApi(Flags.FLAG_RANGING_STACK_ENABLED) 42 public final class UwbRangingParams implements Parcelable { 43 44 private final int mSessionId; 45 46 private final int mSubSessionId; 47 UwbRangingParams(Parcel in)48 private UwbRangingParams(Parcel in) { 49 mSessionId = in.readInt(); 50 mSubSessionId = in.readInt(); 51 mConfigId = in.readInt(); 52 mDeviceAddress = in.readParcelable(UwbAddress.class.getClassLoader()); 53 mSessionKeyInfo = in.readBlob(); 54 mSubSessionKeyInfo = in.readBlob(); 55 mComplexChannel = in.readParcelable(UwbComplexChannel.class.getClassLoader()); 56 mRangingUpdateRate = in.readInt(); 57 mPeerAddress = in.readParcelable(UwbAddress.class.getClassLoader()); 58 mSlotDurationMillis = in.readInt(); 59 } 60 61 @NonNull 62 public static final Creator<UwbRangingParams> CREATOR = new Creator<UwbRangingParams>() { 63 @Override 64 public UwbRangingParams createFromParcel(Parcel in) { 65 return new UwbRangingParams(in); 66 } 67 68 @Override 69 public UwbRangingParams[] newArray(int size) { 70 return new UwbRangingParams[size]; 71 } 72 }; 73 74 @Override describeContents()75 public int describeContents() { 76 return 0; 77 } 78 79 @Override writeToParcel(@ndroidx.annotation.NonNull Parcel dest, int flags)80 public void writeToParcel(@androidx.annotation.NonNull Parcel dest, int flags) { 81 dest.writeInt(mSessionId); 82 dest.writeInt(mSubSessionId); 83 dest.writeInt(mConfigId); 84 dest.writeParcelable(mDeviceAddress, flags); 85 dest.writeBlob(mSessionKeyInfo); 86 dest.writeBlob(mSubSessionKeyInfo); 87 dest.writeParcelable(mComplexChannel, flags); 88 dest.writeInt(mRangingUpdateRate); 89 dest.writeParcelable(mPeerAddress, flags); 90 dest.writeInt(mSlotDurationMillis); 91 } 92 93 /** 94 * Defines the roles that a device can assume within a UWB ranging session. 95 * 96 * @hide 97 */ 98 @Retention(RetentionPolicy.SOURCE) 99 @Target({ElementType.TYPE_USE}) 100 @IntDef({ 101 CONFIG_UNICAST_DS_TWR, 102 CONFIG_MULTICAST_DS_TWR, 103 CONFIG_PROVISIONED_UNICAST_DS_TWR, 104 CONFIG_PROVISIONED_MULTICAST_DS_TWR, 105 CONFIG_PROVISIONED_INDIVIDUAL_MULTICAST_DS_TWR, 106 CONFIG_PROVISIONED_UNICAST_DS_TWR_VERY_FAST, 107 }) 108 public @interface ConfigId { 109 } 110 111 /** 112 * FiRa-defined unicast {@code STATIC STS DS-TWR} ranging, deferred mode, ranging interval 113 * Fast (120ms), Normal (240ms), Infrequent (600ms) 114 */ 115 public static final int CONFIG_UNICAST_DS_TWR = 1; 116 117 /** 118 * FiRa-defined multicast {@code STATIC STS DS-TWR} ranging, deferred mode, ranging interval 119 * Fast (120ms), Normal (200ms), Infrequent (600ms) 120 */ 121 public static final int CONFIG_MULTICAST_DS_TWR = 2; 122 /** Same as {@code CONFIG_UNICAST_DS_TWR}, except P-STS security mode is enabled. */ 123 public static final int CONFIG_PROVISIONED_UNICAST_DS_TWR = 3; 124 /** Same as {@code CONFIG_MULTICAST_DS_TWR}, except P-STS security mode is enabled. */ 125 public static final int CONFIG_PROVISIONED_MULTICAST_DS_TWR = 4; 126 /** 127 * Same as {@code CONFIG_UNICAST_DS_TWR}, except P-STS individual controlee key mode is 128 * enabled. 129 */ 130 public static final int CONFIG_PROVISIONED_INDIVIDUAL_MULTICAST_DS_TWR = 5; 131 132 /** Same as {@code CONFIG_ID_3}, except fast ranging interval is 96 milliseconds. */ 133 public static final int CONFIG_PROVISIONED_UNICAST_DS_TWR_VERY_FAST = 6; 134 135 /** Sub session id not applicable. */ 136 public static final int SUB_SESSION_UNDEFINED = -1; 137 138 @ConfigId 139 private final int mConfigId; 140 141 private final UwbAddress mDeviceAddress; 142 143 private final byte[] mSessionKeyInfo; 144 145 private final byte[] mSubSessionKeyInfo; 146 147 private final UwbComplexChannel mComplexChannel; 148 149 private final UwbAddress mPeerAddress; 150 151 /** 152 * Defines slot supported slot durations. 153 * 154 * @hide 155 */ 156 @Retention(RetentionPolicy.SOURCE) 157 @IntDef({ 158 DURATION_1_MS, 159 DURATION_2_MS, 160 }) 161 public @interface SlotDuration { 162 } 163 164 /** 1 millisecond slot duration */ 165 public static final int DURATION_1_MS = 1; 166 167 /** 2 millisecond slot duration */ 168 public static final int DURATION_2_MS = 2; 169 170 @RangingUpdateRate 171 private final int mRangingUpdateRate; 172 173 @SlotDuration 174 private final int mSlotDurationMillis; 175 UwbRangingParams(Builder builder)176 private UwbRangingParams(Builder builder) { 177 mSessionId = builder.mSessionId; 178 mSubSessionId = builder.mSubSessionId; 179 mConfigId = builder.mConfigId; 180 mDeviceAddress = builder.mDeviceAddress; 181 mSessionKeyInfo = builder.mSessionKeyInfo; 182 mSubSessionKeyInfo = builder.mSubSessionKeyInfo; 183 mComplexChannel = builder.mComplexChannel; 184 mPeerAddress = builder.mPeerAddress; 185 mRangingUpdateRate = builder.mRangingUpdateRate; 186 mSlotDurationMillis = builder.mSlotDuration; 187 } 188 189 /** 190 * Gets the session ID associated with this ranging session. 191 * 192 * @return The session ID as an integer. 193 */ getSessionId()194 public int getSessionId() { 195 return mSessionId; 196 } 197 198 /** 199 * Gets the sub-session ID if applicable for the session. 200 * 201 * @return The sub-session ID as an integer or {@link #SUB_SESSION_UNDEFINED} if not applicable. 202 */ getSubSessionId()203 public int getSubSessionId() { 204 return mSubSessionId; 205 } 206 207 /** 208 * Gets the configuration ID associated with this session. 209 * 210 * @return The configuration ID as an integer. 211 */ 212 @ConfigId getConfigId()213 public int getConfigId() { 214 return mConfigId; 215 } 216 217 /** 218 * Gets the UWB address of the device. 219 * 220 * @return The {@link UwbAddress} of the device. 221 */ 222 @NonNull getDeviceAddress()223 public UwbAddress getDeviceAddress() { 224 return mDeviceAddress; 225 } 226 227 /** 228 * Gets session key information, if available. 229 * 230 * @return A byte array containing session key info, or null if not available. 231 */ 232 @Nullable getSessionKeyInfo()233 public byte[] getSessionKeyInfo() { 234 return mSessionKeyInfo == null ? null : Arrays.copyOf(mSessionKeyInfo, 235 mSessionKeyInfo.length); 236 } 237 238 /** 239 * Gets sub-session key information, if available. 240 * 241 * @return A byte array containing sub-session key info, or null if not available. 242 */ 243 @Nullable getSubSessionKeyInfo()244 public byte[] getSubSessionKeyInfo() { 245 return mSubSessionKeyInfo == null ? null : Arrays.copyOf(mSubSessionKeyInfo, 246 mSubSessionKeyInfo.length); 247 } 248 249 /** 250 * Gets the complex channel information for this session. 251 * 252 * @return A {@link UwbComplexChannel} object containing channel and preamble index. 253 */ 254 @NonNull getComplexChannel()255 public UwbComplexChannel getComplexChannel() { 256 return mComplexChannel; 257 } 258 259 /** 260 * Returns the UwbAddress of the peer device. 261 * 262 * @return A {@link UwbAddress} corresponding to the peer device to range with. 263 */ 264 @NonNull getPeerAddress()265 public UwbAddress getPeerAddress() { 266 return mPeerAddress; 267 } 268 269 /** 270 * Returns the update rate for ranging operations. 271 * 272 * @return The ranging update rate. 273 */ 274 @RangingUpdateRate getRangingUpdateRate()275 public int getRangingUpdateRate() { 276 return mRangingUpdateRate; 277 } 278 279 /** 280 * Returns slot duration of the session. 281 * 282 * @return the slot duration. 283 */ 284 @SlotDuration getSlotDuration()285 public int getSlotDuration() { 286 return mSlotDurationMillis; 287 } 288 289 290 /** 291 * Builder class for creating instances of {@link UwbRangingParams} 292 */ 293 public static final class Builder { 294 private int mSessionId; 295 private int mSubSessionId = SUB_SESSION_UNDEFINED; 296 private int mConfigId; 297 private UwbAddress mDeviceAddress = null; 298 private byte[] mSessionKeyInfo = null; 299 private byte[] mSubSessionKeyInfo = null; 300 private UwbComplexChannel mComplexChannel = new UwbComplexChannel.Builder().build(); 301 private UwbAddress mPeerAddress = null; 302 @RangingUpdateRate 303 private int mRangingUpdateRate = UPDATE_RATE_NORMAL; 304 @SlotDuration 305 private int mSlotDuration = DURATION_2_MS; 306 307 /** 308 * Constructs a new {@link Builder} for creating a ranging session. 309 * 310 * @param sessionId A unique identifier for the session. 311 * @param configId The configuration ID for the ranging parameters. 312 * @param deviceAddress The {@link UwbAddress} representing the device's address. 313 * Must be non-null. 314 * @param peerAddress The {@link UwbAddress} of the peer device. 315 * Must be non-null. 316 * @throws IllegalArgumentException if either {@code deviceAddress} or {@code peerAddress} 317 * is null. 318 */ Builder(int sessionId, @ConfigId int configId, @NonNull UwbAddress deviceAddress, @NonNull UwbAddress peerAddress)319 public Builder(int sessionId, @ConfigId int configId, @NonNull UwbAddress deviceAddress, 320 @NonNull UwbAddress peerAddress) { 321 Objects.requireNonNull(deviceAddress); 322 Objects.requireNonNull(peerAddress); 323 mSessionId = sessionId; 324 mConfigId = configId; 325 mDeviceAddress = deviceAddress; 326 mPeerAddress = peerAddress; 327 } 328 329 /** 330 * Sets the sub-session ID for the ranging session. 331 * 332 * @param subSessionId the sub-session ID, which should be a unique identifier for the 333 * sub-session. 334 * @return this Builder instance for method chaining. 335 */ 336 @NonNull setSubSessionId(int subSessionId)337 public Builder setSubSessionId(int subSessionId) { 338 mSubSessionId = subSessionId; 339 return this; 340 } 341 342 /** 343 * Sets the session key information for secure ranging. 344 * 345 * @param sessionKeyInfo a byte array containing session key information. 346 * @return this Builder instance. 347 * @throws IllegalArgumentException if the provided byte array is null. 348 */ 349 @NonNull setSessionKeyInfo(@onNull byte[] sessionKeyInfo)350 public Builder setSessionKeyInfo(@NonNull byte[] sessionKeyInfo) { 351 Objects.requireNonNull(sessionKeyInfo); 352 mSessionKeyInfo = Arrays.copyOf(sessionKeyInfo, sessionKeyInfo.length); 353 return this; 354 } 355 356 /** 357 * Sets the sub-session key information for secure ranging. 358 * 359 * @param subSessionKeyInfo a byte array containing sub-session key information. 360 * @return this Builder instance. 361 * @throws IllegalArgumentException if the provided map is null. 362 */ 363 @NonNull setSubSessionKeyInfo(@onNull byte[] subSessionKeyInfo)364 public Builder setSubSessionKeyInfo(@NonNull byte[] subSessionKeyInfo) { 365 Objects.requireNonNull(subSessionKeyInfo); 366 mSubSessionKeyInfo = Arrays.copyOf(subSessionKeyInfo, subSessionKeyInfo.length); 367 return this; 368 } 369 370 /** 371 * Sets the complex channel configuration for the ranging session. 372 * 373 * @param complexChannel a non-null {@link UwbComplexChannel} instance representing the 374 * channel and preamble configuration. For better performance always 375 * use a random preamble index for each ranging session. 376 * @return this Builder instance. 377 * @throws IllegalArgumentException if the provided complex channel is null. 378 */ 379 @NonNull setComplexChannel(@onNull UwbComplexChannel complexChannel)380 public Builder setComplexChannel(@NonNull UwbComplexChannel complexChannel) { 381 mComplexChannel = complexChannel; 382 return this; 383 } 384 385 /** 386 * Sets the ranging update rate for the session. 387 * <p> Defaults to {@link RangingUpdateRate#UPDATE_RATE_NORMAL}. 388 * 389 * @param rate the ranging update rate, defined as one of the constants in 390 * {@link RangingUpdateRate}. 391 * @return this Builder instance. 392 */ 393 @NonNull setRangingUpdateRate(@angingUpdateRate int rate)394 public Builder setRangingUpdateRate(@RangingUpdateRate int rate) { 395 mRangingUpdateRate = rate; 396 return this; 397 } 398 399 /** 400 * Sets the slot duration in milliseconds for the ranging session. 401 * <p> Defaults to {@link #DURATION_2_MS}. 402 * 403 * @param durationMs the slot duration {@link SlotDuration} 404 * @return this Builder instance. 405 * @throws IllegalArgumentException if the provided duration is out of range. 406 */ 407 @NonNull setSlotDuration(@lotDuration int durationMs)408 public Builder setSlotDuration(@SlotDuration int durationMs) { 409 mSlotDuration = durationMs; 410 return this; 411 } 412 413 /** 414 * Builds a new instance of {@link UwbRangingParams}. 415 * 416 * @return a new instance of {@link UwbRangingParams} created using the current state of 417 * the builder. 418 */ 419 @NonNull build()420 public UwbRangingParams build() { 421 return new UwbRangingParams(this); 422 } 423 } 424 425 @Override toString()426 public String toString() { 427 return "UwbRangingParams{ " 428 + "mSessionId=" 429 + mSessionId 430 + ", mSubSessionId=" 431 + mSubSessionId 432 + ", mConfigId=" 433 + mConfigId 434 + ", mDeviceAddress=" 435 + mDeviceAddress 436 + ", mSessionKeyInfo=" 437 + Arrays.toString(mSessionKeyInfo) 438 + ", mSubSessionKeyInfo=" 439 + Arrays.toString(mSubSessionKeyInfo) 440 + ", mComplexChannel=" 441 + mComplexChannel 442 + ", mPeerAddress=" 443 + mPeerAddress 444 + ", mRangingUpdateRate=" 445 + mRangingUpdateRate 446 + ", mSlotDurationMillis=" 447 + mSlotDurationMillis 448 + " }"; 449 } 450 451 /** 452 * @hide 453 */ 454 @Override equals(Object o)455 public boolean equals(Object o) { 456 if (this == o) return true; 457 if (!(o instanceof UwbRangingParams that)) return false; 458 return mSessionId == that.mSessionId && mSubSessionId == that.mSubSessionId 459 && mConfigId == that.mConfigId && mRangingUpdateRate == that.mRangingUpdateRate 460 && mSlotDurationMillis == that.mSlotDurationMillis && Objects.equals( 461 mDeviceAddress, that.mDeviceAddress) && Objects.deepEquals(mSessionKeyInfo, 462 that.mSessionKeyInfo) && Objects.deepEquals(mSubSessionKeyInfo, 463 that.mSubSessionKeyInfo) && Objects.equals(mComplexChannel, 464 that.mComplexChannel) && Objects.equals(mPeerAddress, that.mPeerAddress); 465 } 466 467 /** 468 * @hide 469 */ 470 @Override hashCode()471 public int hashCode() { 472 return Objects.hash(mSessionId, mSubSessionId, mConfigId, mDeviceAddress, 473 Arrays.hashCode(mSessionKeyInfo), Arrays.hashCode(mSubSessionKeyInfo), 474 mComplexChannel, 475 mPeerAddress, mRangingUpdateRate, mSlotDurationMillis); 476 } 477 } 478