1 /* 2 * Copyright (C) 2025 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.rtt; 18 19 import android.ranging.RangingDevice; 20 import android.ranging.SessionConfig; 21 import android.ranging.wifi.rtt.RttRangingParams; 22 23 import com.android.server.ranging.RangingTechnology; 24 import com.android.server.ranging.oob.SetConfigurationMessage; 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 @AutoValue 34 public abstract class RttOobConfig implements SetConfigurationMessage.TechnologyOobConfig { 35 36 private static final int MIN_SIZE_BYTES = 6; 37 38 public enum RttSupportedFeatures { 39 RTT_11_MC(1), 40 RTT_11_AZ(2), 41 RTT_UNKNOWN(255); 42 43 public static final ImmutableList<RttSupportedFeatures> FEATURES = 44 ImmutableList.copyOf(RttSupportedFeatures.values()); 45 46 private final int mValue; 47 RttSupportedFeatures(int value)48 RttSupportedFeatures(int value) { 49 this.mValue = value; 50 } 51 getValue()52 public int getValue() { 53 return mValue; 54 } 55 fromValue(int value)56 public static RttSupportedFeatures fromValue(int value) { 57 return value < RTT_11_MC.mValue || value > RTT_11_AZ.mValue ? RTT_UNKNOWN : 58 RttSupportedFeatures.values()[value]; 59 } 60 } 61 62 public enum Bandwidth { 63 BANDWIDTH_20MHZ(0), 64 BANDWIDTH_40MHZ(1), 65 BANDWIDTH_80MHZ(2), 66 BANDWIDTH_160MHZ(3), 67 BANDWIDTH_80MHZ_PLUS_MHZ(4), 68 BANDWIDTH_320MHZ(5), 69 BANDWIDTH_UNDEFINED(255); 70 71 private final int mValue; 72 Bandwidth(int value)73 Bandwidth(int value) { 74 this.mValue = value; 75 } 76 getValue()77 public int getValue() { 78 return mValue; 79 } 80 } 81 parseBytes(byte[] rttConfigBytes)82 public static RttOobConfig parseBytes(byte[] rttConfigBytes) { 83 TechnologyHeader header = TechnologyHeader.parseBytes(rttConfigBytes); 84 85 if (rttConfigBytes.length < MIN_SIZE_BYTES) { 86 throw new IllegalArgumentException( 87 String.format("RttConfig size is %d, expected at least %d", 88 rttConfigBytes.length, MIN_SIZE_BYTES)); 89 } 90 91 if (rttConfigBytes.length < header.getSize()) { 92 throw new IllegalArgumentException( 93 String.format( 94 "RttConfig header size field is %d, but the size of the array is %d", 95 header.getSize(), rttConfigBytes.length)); 96 } 97 98 if (header.getRangingTechnology() != RangingTechnology.RTT) { 99 throw new IllegalArgumentException( 100 String.format( 101 "RttConfig header technology field is %s, expected %s", 102 header.getRangingTechnology(), RangingTechnology.RTT)); 103 } 104 105 int parseCursor = header.getHeaderSize(); 106 int serviceNameSize = rttConfigBytes[parseCursor++]; 107 byte[] serviceNameBytes = Arrays.copyOfRange(rttConfigBytes, parseCursor, 108 parseCursor + serviceNameSize); 109 String serviceName = new String(serviceNameBytes); 110 parseCursor += serviceNameSize; 111 112 int deviceRole = rttConfigBytes[parseCursor++]; 113 boolean usePeriodicRanging = rttConfigBytes[parseCursor++] != 0; 114 115 return builder() 116 .setDeviceRole(deviceRole) 117 .setServiceName(serviceName) 118 .setUsePeriodicRanging(usePeriodicRanging) 119 .build(); 120 } 121 toBytes()122 public final byte[] toBytes() { 123 int size = MIN_SIZE_BYTES + serviceName().length() - 1; 124 return ByteBuffer.allocate(size) 125 .put(RangingTechnology.RTT.toByte()) 126 .put((byte) size) 127 .put((byte) serviceName().length()) 128 .put(serviceName().getBytes()) 129 .put((byte) deviceRole()) 130 .put((byte) (usePeriodicRanging() ? 1 : 0)) 131 .array(); 132 } 133 getSize()134 public int getSize() { 135 return toBytes().length; 136 } 137 toTechnologyConfig(RangingDevice peer, int deviceRole)138 public RttConfig toTechnologyConfig(RangingDevice peer, int deviceRole) { 139 return new RttConfig( 140 deviceRole, 141 new RttRangingParams.Builder(serviceName()).build(), 142 new SessionConfig.Builder().build(), 143 peer); 144 } 145 serviceName()146 public abstract String serviceName(); 147 148 @OobDeviceRole deviceRole()149 public abstract int deviceRole(); 150 usePeriodicRanging()151 public abstract boolean usePeriodicRanging(); 152 153 public @interface OobDeviceRole { 154 int RESPONDER = 0; 155 int INITIATOR = 1; 156 } 157 builder()158 public static Builder builder() { 159 return new AutoValue_RttOobConfig.Builder(); 160 } 161 162 @AutoValue.Builder 163 public abstract static class Builder { setServiceName(String value)164 public abstract Builder setServiceName(String value); 165 setDeviceRole(int value)166 public abstract Builder setDeviceRole(int value); 167 setUsePeriodicRanging(boolean value)168 public abstract Builder setUsePeriodicRanging(boolean value); 169 autoBuild()170 abstract RttOobConfig autoBuild(); 171 build()172 public RttOobConfig build() { 173 return autoBuild(); 174 } 175 176 } 177 } 178