1 /* 2 * Copyright (C) 2021 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.uwb.params; 18 19 import static com.android.server.uwb.config.CapabilityParam.CCC_CHANNEL_5; 20 import static com.android.server.uwb.config.CapabilityParam.CCC_CHANNEL_9; 21 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_12; 22 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_24; 23 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_3; 24 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_4; 25 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_6; 26 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_8; 27 import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_9; 28 import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_CONFIG_MODE_ADAPTIVE; 29 import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_CONFIG_MODE_CONTINUOUS; 30 import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_CONFIG_MODE_NONE; 31 import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_SEQUENCE_AES; 32 import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_SEQUENCE_DEFAULT; 33 import static com.android.server.uwb.config.CapabilityParam.CCC_PRIORITIZED_CHANNEL_LIST; 34 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_CHANNELS; 35 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_CHAPS_PER_SLOT; 36 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_HOPPING_CONFIG_MODES_AND_SEQUENCES; 37 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER; 38 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS; 39 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_PULSE_SHAPE_COMBOS; 40 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_RAN_MULTIPLIER; 41 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_SYNC_CODES; 42 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_UWB_CONFIGS; 43 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_UWBS_MAX_PPM; 44 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_VERSIONS; 45 46 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_12; 47 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_24; 48 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_3; 49 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_4; 50 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_6; 51 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_8; 52 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_9; 53 import static com.google.uwb.support.ccc.CccParams.HOPPING_CONFIG_MODE_ADAPTIVE; 54 import static com.google.uwb.support.ccc.CccParams.HOPPING_CONFIG_MODE_CONTINUOUS; 55 import static com.google.uwb.support.ccc.CccParams.HOPPING_CONFIG_MODE_NONE; 56 import static com.google.uwb.support.ccc.CccParams.HOPPING_SEQUENCE_AES; 57 import static com.google.uwb.support.ccc.CccParams.HOPPING_SEQUENCE_DEFAULT; 58 import static com.google.uwb.support.ccc.CccParams.UWB_CHANNEL_5; 59 import static com.google.uwb.support.ccc.CccParams.UWB_CHANNEL_9; 60 61 import android.util.Log; 62 63 import com.android.server.uwb.UwbInjector; 64 import com.android.server.uwb.config.ConfigParam; 65 66 import com.google.uwb.support.base.Params; 67 import com.google.uwb.support.base.ProtocolVersion; 68 import com.google.uwb.support.ccc.CccProtocolVersion; 69 import com.google.uwb.support.ccc.CccPulseShapeCombo; 70 import com.google.uwb.support.ccc.CccRangingStartedParams; 71 import com.google.uwb.support.ccc.CccRangingStoppedParams; 72 import com.google.uwb.support.ccc.CccSpecificationParams; 73 74 import java.nio.ByteBuffer; 75 import java.nio.ByteOrder; 76 77 /** 78 * CCC decoder 79 */ 80 public class CccDecoder extends TlvDecoder { 81 private static final String TAG = "CccDecoder"; 82 private final UwbInjector mUwbInjector; 83 CccDecoder(UwbInjector uwbInjector)84 public CccDecoder(UwbInjector uwbInjector) { 85 mUwbInjector = uwbInjector; 86 } 87 88 @Override getParams(TlvDecoderBuffer tlvs, Class<T> paramsType, ProtocolVersion protocolVersion)89 public <T extends Params> T getParams(TlvDecoderBuffer tlvs, Class<T> paramsType, 90 ProtocolVersion protocolVersion) 91 throws IllegalArgumentException { 92 if (CccRangingStartedParams.class.equals(paramsType)) { 93 return (T) getCccRangingStartedParamsFromTlvBuffer(tlvs); 94 } 95 if (CccSpecificationParams.class.equals(paramsType)) { 96 return (T) getCccSpecificationParamsFromTlvBuffer(tlvs); 97 } 98 if (CccRangingStoppedParams.class.equals(paramsType)) { 99 return (T) getCccRangingStoppedParamsFromTlvBuffer(tlvs); 100 } 101 return null; 102 } 103 isBitSet(int flags, int mask)104 private static boolean isBitSet(int flags, int mask) { 105 return (flags & mask) != 0; 106 } 107 getCccRangingStartedParamsFromTlvBuffer(TlvDecoderBuffer tlvs)108 private CccRangingStartedParams getCccRangingStartedParamsFromTlvBuffer(TlvDecoderBuffer tlvs) { 109 byte[] hopModeKey = tlvs.getByteArray(ConfigParam.HOP_MODE_KEY); 110 int hopModeKeyInt = ByteBuffer.wrap(hopModeKey).order(ByteOrder.LITTLE_ENDIAN).getInt(); 111 long uwbTime0; 112 // Backwards compatibility with vendors who were using Google defined 113 // UWB_TIME0 TLV param. 114 try { 115 uwbTime0 = tlvs.getLong(ConfigParam.UWB_TIME0); 116 } catch (IllegalArgumentException e) { 117 uwbTime0 = tlvs.getLong(ConfigParam.UWB_INITIATION_TIME); 118 } 119 120 return new CccRangingStartedParams.Builder() 121 // STS_Index0 0 - 0x3FFFFFFFF 122 .setStartingStsIndex(tlvs.getInt(ConfigParam.STS_INDEX)) 123 .setHopModeKey(hopModeKeyInt) 124 // UWB_Time0 0 - 0xFFFFFFFFFFFFFFFF UWB_INITIATION_TIME 125 .setUwbTime0(uwbTime0) 126 // RANGING_INTERVAL = RAN_Multiplier * 96 127 .setRanMultiplier(tlvs.getInt(ConfigParam.RANGING_INTERVAL) / 96) 128 .setSyncCodeIndex(tlvs.getByte(ConfigParam.PREAMBLE_CODE_INDEX)) 129 .build(); 130 } 131 getCccSpecificationParamsFromTlvBuffer(TlvDecoderBuffer tlvs)132 private CccSpecificationParams getCccSpecificationParamsFromTlvBuffer(TlvDecoderBuffer tlvs) { 133 CccSpecificationParams.Builder builder = new CccSpecificationParams.Builder(); 134 byte[] versions = tlvs.getByteArray(CCC_SUPPORTED_VERSIONS); 135 if (versions.length % 2 != 0) { 136 throw new IllegalArgumentException("Invalid supported protocol versions len " 137 + versions.length); 138 } 139 for (int i = 0; i < versions.length; i += 2) { 140 builder.addProtocolVersion(CccProtocolVersion.fromBytes(versions, i)); 141 } 142 byte[] configs = tlvs.getByteArray(CCC_SUPPORTED_UWB_CONFIGS); 143 for (int i = 0; i < configs.length; i++) { 144 builder.addUwbConfig(configs[i]); 145 } 146 byte[] pulse_shape_combos = tlvs.getByteArray(CCC_SUPPORTED_PULSE_SHAPE_COMBOS); 147 for (int i = 0; i < pulse_shape_combos.length; i++) { 148 builder.addPulseShapeCombo(CccPulseShapeCombo.fromBytes(pulse_shape_combos, i)); 149 } 150 int supportedRanMultiplier; 151 try { 152 supportedRanMultiplier = tlvs.getInt(CCC_SUPPORTED_RAN_MULTIPLIER); 153 } catch (IllegalArgumentException e) { 154 Log.w(TAG, "CCC_SUPPORTED_RAN_MULTIPLIER not a 4 byte value"); 155 // Try for single byte 156 supportedRanMultiplier = tlvs.getByte(CCC_SUPPORTED_RAN_MULTIPLIER); 157 } 158 builder.setRanMultiplier(supportedRanMultiplier); 159 160 byte chapsPerslot = tlvs.getByte(CCC_SUPPORTED_CHAPS_PER_SLOT); 161 if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_3)) { 162 builder.addChapsPerSlot(CHAPS_PER_SLOT_3); 163 } 164 if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_4)) { 165 builder.addChapsPerSlot(CHAPS_PER_SLOT_4); 166 } 167 if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_6)) { 168 builder.addChapsPerSlot(CHAPS_PER_SLOT_6); 169 } 170 if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_8)) { 171 builder.addChapsPerSlot(CHAPS_PER_SLOT_8); 172 } 173 if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_9)) { 174 builder.addChapsPerSlot(CHAPS_PER_SLOT_9); 175 } 176 if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_12)) { 177 builder.addChapsPerSlot(CHAPS_PER_SLOT_12); 178 } 179 if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_24)) { 180 builder.addChapsPerSlot(CHAPS_PER_SLOT_24); 181 } 182 if (mUwbInjector.getDeviceConfigFacade().isCccSupportedSyncCodesLittleEndian()) { 183 byte[] syncCodes = tlvs.getByteArray(CCC_SUPPORTED_SYNC_CODES); 184 for (int byteIndex = 0; byteIndex < syncCodes.length; byteIndex++) { 185 byte syncCodeByte = syncCodes[byteIndex]; 186 for (int bitIndex = 0; bitIndex < 8; bitIndex++) { 187 if ((syncCodeByte & (1 << bitIndex)) != 0) { 188 int syncCodeValue = (byteIndex * 8) + bitIndex + 1; 189 builder.addSyncCode(syncCodeValue); 190 } 191 } 192 } 193 } else { 194 int syncCodes = ByteBuffer.wrap(tlvs.getByteArray(CCC_SUPPORTED_SYNC_CODES)).getInt(); 195 for (int i = 0; i < 32; i++) { 196 if (isBitSet(syncCodes, 1 << i)) { 197 builder.addSyncCode(i + 1); 198 } 199 } 200 } 201 202 try { 203 byte[] prioritizedChannels = tlvs.getByteArray(CCC_PRIORITIZED_CHANNEL_LIST); 204 for (byte prioritizedChannel : prioritizedChannels) { 205 builder.addChannel(prioritizedChannel); 206 } 207 } catch (IllegalArgumentException e) { 208 Log.w(TAG, "CCC_PRIORITIZED_CHANNEL_LIST not found"); 209 byte channels = tlvs.getByte(CCC_SUPPORTED_CHANNELS); 210 if (isBitSet(channels, CCC_CHANNEL_5)) { 211 builder.addChannel(UWB_CHANNEL_5); 212 } 213 if (isBitSet(channels, CCC_CHANNEL_9)) { 214 builder.addChannel(UWB_CHANNEL_9); 215 } 216 } 217 byte hoppingConfigModesAndSequences = 218 tlvs.getByte(CCC_SUPPORTED_HOPPING_CONFIG_MODES_AND_SEQUENCES); 219 if (isBitSet(hoppingConfigModesAndSequences, CCC_HOPPING_CONFIG_MODE_NONE)) { 220 builder.addHoppingConfigMode(HOPPING_CONFIG_MODE_NONE); 221 } 222 if (isBitSet(hoppingConfigModesAndSequences, CCC_HOPPING_CONFIG_MODE_CONTINUOUS)) { 223 builder.addHoppingConfigMode(HOPPING_CONFIG_MODE_CONTINUOUS); 224 } 225 if (isBitSet(hoppingConfigModesAndSequences, CCC_HOPPING_CONFIG_MODE_ADAPTIVE)) { 226 builder.addHoppingConfigMode(HOPPING_CONFIG_MODE_ADAPTIVE); 227 } 228 if (isBitSet(hoppingConfigModesAndSequences, CCC_HOPPING_SEQUENCE_AES)) { 229 builder.addHoppingSequence(HOPPING_SEQUENCE_AES); 230 } 231 if (isBitSet(hoppingConfigModesAndSequences, CCC_HOPPING_SEQUENCE_DEFAULT)) { 232 builder.addHoppingSequence(HOPPING_SEQUENCE_DEFAULT); 233 } 234 235 try { 236 int maxRangingSessionNumber = tlvs.getInt(CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER); 237 builder.setMaxRangingSessionNumber(maxRangingSessionNumber); 238 } catch (IllegalArgumentException e) { 239 Log.w(TAG, "SUPPORTED_MAX_RANGING_SESSION_NUMBER not found"); 240 } 241 242 try { 243 int minUwbInitiationTimeMs = tlvs.getInt(CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS); 244 builder.setMinUwbInitiationTimeMs(minUwbInitiationTimeMs); 245 } catch (IllegalArgumentException e) { 246 Log.w(TAG, "SUPPORTED_MIN_UWB_INITIATION_TIME_MS not found"); 247 } 248 249 // Attempt to parse the UWBS_MAX_PPM as a short, since the CCC spec R3 defines the 250 // field Device_max_PPM field (in the TimeSync message) as a 2-octet field. 251 try { 252 short uwbsMaxPPM = tlvs.getShort(CCC_SUPPORTED_UWBS_MAX_PPM); 253 builder.setUwbsMaxPPM(uwbsMaxPPM); 254 } catch (IllegalArgumentException e) { 255 Log.w(TAG, "CCC_SUPPORTED_UWBS_MAX_PPM not found"); 256 } 257 258 return builder.build(); 259 } 260 getCccRangingStoppedParamsFromTlvBuffer(TlvDecoderBuffer tlvs)261 private CccRangingStoppedParams getCccRangingStoppedParamsFromTlvBuffer(TlvDecoderBuffer tlvs) { 262 int lastStsIndexUsed = tlvs.getInt(ConfigParam.LAST_STS_INDEX_USED); 263 return new CccRangingStoppedParams.Builder() 264 .setLastStsIndexUsed(lastStsIndexUsed) 265 .build(); 266 } 267 } 268