| /* |
| * Copyright (C) 2021 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.google.uwb.support.fira; |
| |
| import static com.android.internal.util.Preconditions.checkArgument; |
| |
| import static java.util.Objects.requireNonNull; |
| |
| import android.os.PersistableBundle; |
| import android.uwb.RangingSession; |
| import android.uwb.UwbAddress; |
| |
| import androidx.annotation.FloatRange; |
| import androidx.annotation.Nullable; |
| |
| /** |
| * UWB parameters used to reconfigure a FiRa session. Supports peer adding/removing. |
| * |
| * <p>This is passed as a bundle to the service API {@link RangingSession#reconfigure}. |
| */ |
| public class FiraRangingReconfigureParams extends FiraParams { |
| private static final int BUNDLE_VERSION_1 = 1; |
| private static final int BUNDLE_VERSION_CURRENT = BUNDLE_VERSION_1; |
| |
| @Nullable @MulticastListUpdateAction private final Integer mAction; |
| @Nullable private final UwbAddress[] mAddressList; |
| @Nullable private final int[] mSubSessionIdList; |
| |
| @Nullable private final Integer mBlockStrideLength; |
| |
| @Nullable @RangeDataNtfConfig private final Integer mRangeDataNtfConfig; |
| @Nullable private final Integer mRangeDataProximityNear; |
| @Nullable private final Integer mRangeDataProximityFar; |
| @Nullable private final Double mRangeDataAoaAzimuthLower; |
| @Nullable private final Double mRangeDataAoaAzimuthUpper; |
| @Nullable private final Double mRangeDataAoaElevationLower; |
| @Nullable private final Double mRangeDataAoaElevationUpper; |
| |
| private static final String KEY_ACTION = "action"; |
| private static final String KEY_MAC_ADDRESS_MODE = "mac_address_mode"; |
| private static final String KEY_ADDRESS_LIST = "address_list"; |
| private static final String KEY_SUB_SESSION_ID_LIST = "sub_session_id_list"; |
| private static final String KEY_UPDATE_BLOCK_STRIDE_LENGTH = "update_block_stride_length"; |
| private static final String KEY_UPDATE_RANGE_DATA_NTF_CONFIG = "update_range_data_ntf_config"; |
| private static final String KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_NEAR = |
| "update_range_data_proximity_near"; |
| private static final String KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_FAR = |
| "update_range_data_proximity_far"; |
| private static final String KEY_UPDATE_RANGE_DATA_NTF_AOA_AZIMUTH_LOWER = |
| "range_data_aoa_azimuth_lower"; |
| private static final String KEY_UPDATE_RANGE_DATA_NTF_AOA_AZIMUTH_UPPER = |
| "range_data_aoa_azimuth_upper"; |
| private static final String KEY_UPDATE_RANGE_DATA_NTF_AOA_ELEVATION_LOWER = |
| "range_data_aoa_elevation_lower"; |
| private static final String KEY_UPDATE_RANGE_DATA_NTF_AOA_ELEVATION_UPPER = |
| "range_data_aoa_elevation_upper"; |
| |
| private FiraRangingReconfigureParams( |
| @Nullable @MulticastListUpdateAction Integer action, |
| @Nullable UwbAddress[] addressList, |
| @Nullable int[] subSessionIdList, |
| @Nullable Integer blockStrideLength, |
| @Nullable Integer rangeDataNtfConfig, |
| @Nullable Integer rangeDataProximityNear, |
| @Nullable Integer rangeDataProximityFar, |
| @Nullable Double rangeDataAoaAzimuthLower, |
| @Nullable Double rangeDataAoaAzimuthUpper, |
| @Nullable Double rangeDataAoaElevationLower, |
| @Nullable Double rangeDataAoaElevationUpper) { |
| mAction = action; |
| mAddressList = addressList; |
| mSubSessionIdList = subSessionIdList; |
| mBlockStrideLength = blockStrideLength; |
| mRangeDataNtfConfig = rangeDataNtfConfig; |
| mRangeDataProximityNear = rangeDataProximityNear; |
| mRangeDataProximityFar = rangeDataProximityFar; |
| mRangeDataAoaAzimuthLower = rangeDataAoaAzimuthLower; |
| mRangeDataAoaAzimuthUpper = rangeDataAoaAzimuthUpper; |
| mRangeDataAoaElevationLower = rangeDataAoaElevationLower; |
| mRangeDataAoaElevationUpper = rangeDataAoaElevationUpper; |
| } |
| |
| @Override |
| protected int getBundleVersion() { |
| return BUNDLE_VERSION_CURRENT; |
| } |
| |
| @Nullable |
| @MulticastListUpdateAction |
| public Integer getAction() { |
| return mAction; |
| } |
| |
| @Nullable |
| public UwbAddress[] getAddressList() { |
| return mAddressList; |
| } |
| |
| @Nullable |
| public int[] getSubSessionIdList() { |
| return mSubSessionIdList; |
| } |
| |
| @Nullable |
| public Integer getBlockStrideLength() { |
| return mBlockStrideLength; |
| } |
| |
| @Nullable |
| public Integer getRangeDataNtfConfig() { |
| return mRangeDataNtfConfig; |
| } |
| |
| @Nullable |
| public Integer getRangeDataProximityNear() { |
| return mRangeDataProximityNear; |
| } |
| |
| @Nullable |
| public Integer getRangeDataProximityFar() { |
| return mRangeDataProximityFar; |
| } |
| |
| @Nullable |
| public Double getRangeDataAoaAzimuthLower() { |
| return mRangeDataAoaAzimuthLower; |
| } |
| |
| @Nullable |
| public Double getRangeDataAoaAzimuthUpper() { |
| return mRangeDataAoaAzimuthUpper; |
| } |
| |
| @Nullable |
| public Double getRangeDataAoaElevationLower() { |
| return mRangeDataAoaElevationLower; |
| } |
| |
| @Nullable |
| public Double getRangeDataAoaElevationUpper() { |
| return mRangeDataAoaElevationUpper; |
| } |
| |
| @Override |
| public PersistableBundle toBundle() { |
| PersistableBundle bundle = super.toBundle(); |
| if (mAction != null) { |
| requireNonNull(mAddressList); |
| bundle.putInt(KEY_ACTION, mAction); |
| |
| long[] addressList = new long[mAddressList.length]; |
| int i = 0; |
| for (UwbAddress address : mAddressList) { |
| addressList[i++] = uwbAddressToLong(address); |
| } |
| int macAddressMode = MAC_ADDRESS_MODE_2_BYTES; |
| if (mAddressList[0].size() == UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH) { |
| macAddressMode = MAC_ADDRESS_MODE_8_BYTES; |
| } |
| bundle.putInt(KEY_MAC_ADDRESS_MODE, macAddressMode); |
| bundle.putLongArray(KEY_ADDRESS_LIST, addressList); |
| bundle.putIntArray(KEY_SUB_SESSION_ID_LIST, mSubSessionIdList); |
| } |
| |
| if (mBlockStrideLength != null) { |
| bundle.putInt(KEY_UPDATE_BLOCK_STRIDE_LENGTH, mBlockStrideLength); |
| } |
| |
| if (mRangeDataNtfConfig != null) { |
| bundle.putInt(KEY_UPDATE_RANGE_DATA_NTF_CONFIG, mRangeDataNtfConfig); |
| } |
| |
| if (mRangeDataProximityNear != null) { |
| bundle.putInt(KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_NEAR, mRangeDataProximityNear); |
| } |
| |
| if (mRangeDataProximityFar != null) { |
| bundle.putInt(KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_FAR, mRangeDataProximityFar); |
| } |
| |
| if (mRangeDataAoaAzimuthLower != null) { |
| bundle.putDouble(KEY_UPDATE_RANGE_DATA_NTF_AOA_AZIMUTH_LOWER, |
| mRangeDataAoaAzimuthLower); |
| } |
| |
| if (mRangeDataAoaAzimuthUpper != null) { |
| bundle.putDouble(KEY_UPDATE_RANGE_DATA_NTF_AOA_AZIMUTH_UPPER, |
| mRangeDataAoaAzimuthUpper); |
| } |
| |
| if (mRangeDataAoaElevationLower != null) { |
| bundle.putDouble(KEY_UPDATE_RANGE_DATA_NTF_AOA_ELEVATION_LOWER, |
| mRangeDataAoaElevationLower); |
| } |
| |
| if (mRangeDataAoaElevationUpper != null) { |
| bundle.putDouble(KEY_UPDATE_RANGE_DATA_NTF_AOA_ELEVATION_UPPER, |
| mRangeDataAoaElevationUpper); |
| } |
| |
| return bundle; |
| } |
| |
| public static FiraRangingReconfigureParams fromBundle(PersistableBundle bundle) { |
| if (!isCorrectProtocol(bundle)) { |
| throw new IllegalArgumentException("Invalid protocol"); |
| } |
| |
| switch (getBundleVersion(bundle)) { |
| case BUNDLE_VERSION_1: |
| return parseVersion1(bundle); |
| |
| default: |
| throw new IllegalArgumentException("Invalid bundle version"); |
| } |
| } |
| |
| private static FiraRangingReconfigureParams parseVersion1(PersistableBundle bundle) { |
| FiraRangingReconfigureParams.Builder builder = new FiraRangingReconfigureParams.Builder(); |
| if (bundle.containsKey(KEY_ACTION)) { |
| int macAddressMode = bundle.getInt(KEY_MAC_ADDRESS_MODE); |
| int addressByteLength = UwbAddress.SHORT_ADDRESS_BYTE_LENGTH; |
| if (macAddressMode == MAC_ADDRESS_MODE_8_BYTES) { |
| addressByteLength = UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH; |
| } |
| |
| long[] addresses = bundle.getLongArray(KEY_ADDRESS_LIST); |
| UwbAddress[] addressList = new UwbAddress[addresses.length]; |
| for (int i = 0; i < addresses.length; i++) { |
| addressList[i] = longToUwbAddress(addresses[i], addressByteLength); |
| } |
| builder.setAction(bundle.getInt(KEY_ACTION)) |
| .setAddressList(addressList) |
| .setSubSessionIdList(bundle.getIntArray(KEY_SUB_SESSION_ID_LIST)); |
| } |
| |
| if (bundle.containsKey(KEY_UPDATE_BLOCK_STRIDE_LENGTH)) { |
| builder.setBlockStrideLength(bundle.getInt(KEY_UPDATE_BLOCK_STRIDE_LENGTH)); |
| } |
| |
| if (bundle.containsKey(KEY_UPDATE_RANGE_DATA_NTF_CONFIG)) { |
| builder.setRangeDataNtfConfig(bundle.getInt(KEY_UPDATE_RANGE_DATA_NTF_CONFIG)); |
| } |
| |
| if (bundle.containsKey(KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_NEAR)) { |
| builder.setRangeDataProximityNear( |
| bundle.getInt(KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_NEAR)); |
| } |
| |
| if (bundle.containsKey(KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_FAR)) { |
| builder.setRangeDataProximityFar( |
| bundle.getInt(KEY_UPDATE_RANGE_DATA_NTF_PROXIMITY_FAR)); |
| } |
| |
| if (bundle.containsKey(KEY_UPDATE_RANGE_DATA_NTF_AOA_AZIMUTH_LOWER)) { |
| builder.setRangeDataAoaAzimuthLower( |
| bundle.getDouble(KEY_UPDATE_RANGE_DATA_NTF_AOA_AZIMUTH_LOWER)); |
| } |
| |
| if (bundle.containsKey(KEY_UPDATE_RANGE_DATA_NTF_AOA_AZIMUTH_UPPER)) { |
| builder.setRangeDataAoaAzimuthUpper( |
| bundle.getDouble(KEY_UPDATE_RANGE_DATA_NTF_AOA_AZIMUTH_UPPER)); |
| } |
| |
| if (bundle.containsKey(KEY_UPDATE_RANGE_DATA_NTF_AOA_ELEVATION_LOWER)) { |
| builder.setRangeDataAoaElevationLower( |
| bundle.getDouble(KEY_UPDATE_RANGE_DATA_NTF_AOA_ELEVATION_LOWER)); |
| } |
| |
| if (bundle.containsKey(KEY_UPDATE_RANGE_DATA_NTF_AOA_ELEVATION_UPPER)) { |
| builder.setRangeDataAoaElevationUpper( |
| bundle.getDouble(KEY_UPDATE_RANGE_DATA_NTF_AOA_ELEVATION_UPPER)); |
| } |
| return builder.build(); |
| } |
| |
| /** Builder */ |
| public static class Builder { |
| @Nullable private Integer mAction = null; |
| @Nullable private UwbAddress[] mAddressList = null; |
| @Nullable private int[] mSubSessionIdList = null; |
| |
| @Nullable private Integer mBlockStrideLength = null; |
| |
| @Nullable private Integer mRangeDataNtfConfig = null; |
| @Nullable private Integer mRangeDataProximityNear = null; |
| @Nullable private Integer mRangeDataProximityFar = null; |
| @Nullable private Double mRangeDataAoaAzimuthLower = null; |
| @Nullable private Double mRangeDataAoaAzimuthUpper = null; |
| @Nullable private Double mRangeDataAoaElevationLower = null; |
| @Nullable private Double mRangeDataAoaElevationUpper = null; |
| |
| public FiraRangingReconfigureParams.Builder setAction( |
| @MulticastListUpdateAction int action) { |
| mAction = action; |
| return this; |
| } |
| |
| public FiraRangingReconfigureParams.Builder setAddressList(UwbAddress[] addressList) { |
| mAddressList = addressList; |
| return this; |
| } |
| |
| public FiraRangingReconfigureParams.Builder setSubSessionIdList(int[] subSessionIdList) { |
| mSubSessionIdList = subSessionIdList; |
| return this; |
| } |
| |
| public FiraRangingReconfigureParams.Builder setBlockStrideLength(int blockStrideLength) { |
| mBlockStrideLength = blockStrideLength; |
| return this; |
| } |
| |
| public FiraRangingReconfigureParams.Builder setRangeDataNtfConfig(int rangeDataNtfConfig) { |
| mRangeDataNtfConfig = rangeDataNtfConfig; |
| return this; |
| } |
| |
| public FiraRangingReconfigureParams.Builder setRangeDataProximityNear( |
| int rangeDataProximityNear) { |
| mRangeDataProximityNear = rangeDataProximityNear; |
| return this; |
| } |
| |
| public FiraRangingReconfigureParams.Builder setRangeDataProximityFar( |
| int rangeDataProximityFar) { |
| mRangeDataProximityFar = rangeDataProximityFar; |
| return this; |
| } |
| |
| public Builder setRangeDataAoaAzimuthLower( |
| @FloatRange(from = RANGE_DATA_NTF_AOA_AZIMUTH_LOWER_DEFAULT, |
| to = RANGE_DATA_NTF_AOA_AZIMUTH_UPPER_DEFAULT) |
| double rangeDataAoaAzimuthLower) { |
| mRangeDataAoaAzimuthLower = rangeDataAoaAzimuthLower; |
| return this; |
| } |
| |
| public Builder setRangeDataAoaAzimuthUpper( |
| @FloatRange(from = RANGE_DATA_NTF_AOA_AZIMUTH_LOWER_DEFAULT, |
| to = RANGE_DATA_NTF_AOA_AZIMUTH_UPPER_DEFAULT) |
| double rangeDataAoaAzimuthUpper) { |
| mRangeDataAoaAzimuthUpper = rangeDataAoaAzimuthUpper; |
| return this; |
| } |
| |
| public Builder setRangeDataAoaElevationLower( |
| @FloatRange(from = RANGE_DATA_NTF_AOA_ELEVATION_LOWER_DEFAULT, |
| to = RANGE_DATA_NTF_AOA_ELEVATION_UPPER_DEFAULT) |
| double rangeDataAoaElevationLower) { |
| mRangeDataAoaElevationLower = rangeDataAoaElevationLower; |
| return this; |
| } |
| |
| public Builder setRangeDataAoaElevationUpper( |
| @FloatRange(from = RANGE_DATA_NTF_AOA_ELEVATION_LOWER_DEFAULT, |
| to = RANGE_DATA_NTF_AOA_ELEVATION_UPPER_DEFAULT) |
| double rangeDataAoaElevationUpper) { |
| mRangeDataAoaElevationUpper = rangeDataAoaElevationUpper; |
| return this; |
| } |
| |
| private void checkAddressList() { |
| checkArgument(mAddressList != null && mAddressList.length > 0); |
| for (UwbAddress uwbAddress : mAddressList) { |
| requireNonNull(uwbAddress); |
| checkArgument(uwbAddress.size() == UwbAddress.SHORT_ADDRESS_BYTE_LENGTH); |
| } |
| |
| checkArgument( |
| mSubSessionIdList == null || mSubSessionIdList.length == mAddressList.length); |
| } |
| |
| private void checkRangeDataNtfConfig() { |
| if (mRangeDataNtfConfig == null) { |
| return; |
| } |
| if (mRangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_DISABLE) { |
| checkArgument(mRangeDataProximityNear == null); |
| checkArgument(mRangeDataProximityFar == null); |
| checkArgument(mRangeDataAoaAzimuthLower == null); |
| checkArgument(mRangeDataAoaAzimuthUpper == null); |
| checkArgument(mRangeDataAoaElevationLower == null); |
| checkArgument(mRangeDataAoaElevationUpper == null); |
| } else if (mRangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_LEVEL_TRIG |
| || mRangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_EDGE_TRIG) { |
| checkArgument(mRangeDataProximityNear != null |
| || mRangeDataProximityFar != null); |
| checkArgument(mRangeDataAoaAzimuthLower == null); |
| checkArgument(mRangeDataAoaAzimuthUpper == null); |
| checkArgument(mRangeDataAoaElevationLower == null); |
| checkArgument(mRangeDataAoaElevationUpper == null); |
| } else if (mRangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_AOA_LEVEL_TRIG |
| || mRangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_AOA_EDGE_TRIG) { |
| checkArgument(mRangeDataProximityNear == null); |
| checkArgument(mRangeDataProximityFar == null); |
| checkArgument((mRangeDataAoaAzimuthLower != null |
| && mRangeDataAoaAzimuthUpper != null) |
| || (mRangeDataAoaElevationLower != null |
| && mRangeDataAoaElevationUpper != null)); |
| } else if (mRangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_LEVEL_TRIG |
| || mRangeDataNtfConfig |
| == RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_EDGE_TRIG) { |
| checkArgument(mRangeDataProximityNear != null |
| || mRangeDataProximityFar != null |
| || (mRangeDataAoaAzimuthLower != null |
| && mRangeDataAoaAzimuthUpper != null) |
| || (mRangeDataAoaElevationLower != null |
| && mRangeDataAoaElevationUpper != null)); |
| } |
| } |
| |
| public FiraRangingReconfigureParams build() { |
| if (mAction != null) { |
| checkAddressList(); |
| // Either update the address list or update ranging parameters. Not both. |
| checkArgument( |
| mBlockStrideLength == null |
| && mRangeDataNtfConfig == null |
| && mRangeDataProximityNear == null |
| && mRangeDataProximityFar == null |
| && mRangeDataAoaAzimuthLower == null |
| && mRangeDataAoaAzimuthUpper == null |
| && mRangeDataAoaElevationLower == null |
| && mRangeDataAoaElevationUpper == null); |
| } else { |
| checkRangeDataNtfConfig(); |
| checkArgument( |
| mBlockStrideLength != null |
| || mRangeDataNtfConfig != null |
| || mRangeDataProximityNear != null |
| || mRangeDataProximityFar != null |
| || mRangeDataAoaAzimuthLower == null |
| || mRangeDataAoaAzimuthUpper == null |
| || mRangeDataAoaElevationLower == null |
| || mRangeDataAoaElevationUpper == null); |
| } |
| |
| return new FiraRangingReconfigureParams( |
| mAction, |
| mAddressList, |
| mSubSessionIdList, |
| mBlockStrideLength, |
| mRangeDataNtfConfig, |
| mRangeDataProximityNear, |
| mRangeDataProximityFar, |
| mRangeDataAoaAzimuthLower, |
| mRangeDataAoaAzimuthUpper, |
| mRangeDataAoaElevationLower, |
| mRangeDataAoaElevationUpper); |
| } |
| } |
| } |