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_SUPPORTED_CHANNELS; 34 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_CHAPS_PER_SLOT; 35 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_HOPPING_CONFIG_MODES_AND_SEQUENCES; 36 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER; 37 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS; 38 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_PULSE_SHAPE_COMBOS; 39 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_RAN_MULTIPLIER; 40 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_SYNC_CODES; 41 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_UWB_CONFIGS; 42 import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_VERSIONS; 43 44 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_12; 45 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_24; 46 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_3; 47 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_4; 48 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_6; 49 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_8; 50 import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_9; 51 import static com.google.uwb.support.ccc.CccParams.HOPPING_CONFIG_MODE_ADAPTIVE; 52 import static com.google.uwb.support.ccc.CccParams.HOPPING_CONFIG_MODE_CONTINUOUS; 53 import static com.google.uwb.support.ccc.CccParams.HOPPING_CONFIG_MODE_NONE; 54 import static com.google.uwb.support.ccc.CccParams.HOPPING_SEQUENCE_AES; 55 import static com.google.uwb.support.ccc.CccParams.HOPPING_SEQUENCE_DEFAULT; 56 import static com.google.uwb.support.ccc.CccParams.UWB_CHANNEL_5; 57 import static com.google.uwb.support.ccc.CccParams.UWB_CHANNEL_9; 58 59 import android.util.Log; 60 61 import com.android.server.uwb.config.ConfigParam; 62 63 import com.google.uwb.support.base.Params; 64 import com.google.uwb.support.ccc.CccProtocolVersion; 65 import com.google.uwb.support.ccc.CccPulseShapeCombo; 66 import com.google.uwb.support.ccc.CccRangingStartedParams; 67 import com.google.uwb.support.ccc.CccSpecificationParams; 68 69 import java.nio.ByteBuffer; 70 import java.nio.ByteOrder; 71 72 /** 73 * CCC decoder 74 */ 75 public class CccDecoder extends TlvDecoder { 76 private static final String TAG = "CccDecoder"; 77 78 @Override getParams(TlvDecoderBuffer tlvs, Class<T> paramsType)79 public <T extends Params> T getParams(TlvDecoderBuffer tlvs, Class<T> paramsType) 80 throws IllegalArgumentException { 81 if (CccRangingStartedParams.class.equals(paramsType)) { 82 return (T) getCccRangingStartedParamsFromTlvBuffer(tlvs); 83 } 84 if (CccSpecificationParams.class.equals(paramsType)) { 85 return (T) getCccSpecificationParamsFromTlvBuffer(tlvs); 86 } 87 return null; 88 } 89 isBitSet(int flags, int mask)90 private static boolean isBitSet(int flags, int mask) { 91 return (flags & mask) != 0; 92 } 93 getCccRangingStartedParamsFromTlvBuffer(TlvDecoderBuffer tlvs)94 private CccRangingStartedParams getCccRangingStartedParamsFromTlvBuffer(TlvDecoderBuffer tlvs) { 95 byte[] hopModeKey = tlvs.getByteArray(ConfigParam.HOP_MODE_KEY); 96 int hopModeKeyInt = ByteBuffer.wrap(hopModeKey).order(ByteOrder.LITTLE_ENDIAN).getInt(); 97 return new CccRangingStartedParams.Builder() 98 // STS_Index0 0 - 0x3FFFFFFFF 99 .setStartingStsIndex(tlvs.getInt(ConfigParam.STS_INDEX)) 100 .setHopModeKey(hopModeKeyInt) 101 // UWB_Time0 0 - 0xFFFFFFFFFFFFFFFF UWB_INITIATION_TIME 102 .setUwbTime0(tlvs.getLong(ConfigParam.UWB_TIME0)) 103 // RANGING_INTERVAL = RAN_Multiplier * 96 104 .setRanMultiplier(tlvs.getInt(ConfigParam.RANGING_INTERVAL) / 96) 105 .setSyncCodeIndex(tlvs.getByte(ConfigParam.PREAMBLE_CODE_INDEX)) 106 .build(); 107 } 108 getCccSpecificationParamsFromTlvBuffer(TlvDecoderBuffer tlvs)109 private CccSpecificationParams getCccSpecificationParamsFromTlvBuffer(TlvDecoderBuffer tlvs) { 110 CccSpecificationParams.Builder builder = new CccSpecificationParams.Builder(); 111 byte[] versions = tlvs.getByteArray(CCC_SUPPORTED_VERSIONS); 112 if (versions.length % 2 != 0) { 113 throw new IllegalArgumentException("Invalid supported protocol versions len " 114 + versions.length); 115 } 116 for (int i = 0; i < versions.length; i += 2) { 117 builder.addProtocolVersion(CccProtocolVersion.fromBytes(versions, i)); 118 } 119 byte[] configs = tlvs.getByteArray(CCC_SUPPORTED_UWB_CONFIGS); 120 for (int i = 0; i < configs.length; i++) { 121 builder.addUwbConfig(configs[i]); 122 } 123 byte[] pulse_shape_combos = tlvs.getByteArray(CCC_SUPPORTED_PULSE_SHAPE_COMBOS); 124 for (int i = 0; i < pulse_shape_combos.length; i++) { 125 builder.addPulseShapeCombo(CccPulseShapeCombo.fromBytes(pulse_shape_combos, i)); 126 } 127 builder.setRanMultiplier(tlvs.getInt(CCC_SUPPORTED_RAN_MULTIPLIER)); 128 byte chapsPerslot = tlvs.getByte(CCC_SUPPORTED_CHAPS_PER_SLOT); 129 if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_3)) { 130 builder.addChapsPerSlot(CHAPS_PER_SLOT_3); 131 } 132 if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_4)) { 133 builder.addChapsPerSlot(CHAPS_PER_SLOT_4); 134 } 135 if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_6)) { 136 builder.addChapsPerSlot(CHAPS_PER_SLOT_6); 137 } 138 if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_8)) { 139 builder.addChapsPerSlot(CHAPS_PER_SLOT_8); 140 } 141 if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_9)) { 142 builder.addChapsPerSlot(CHAPS_PER_SLOT_9); 143 } 144 if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_12)) { 145 builder.addChapsPerSlot(CHAPS_PER_SLOT_12); 146 } 147 if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_24)) { 148 builder.addChapsPerSlot(CHAPS_PER_SLOT_24); 149 } 150 // Don't use TlvDecodeBuffer#getInt() to avoid conversion to little endian. 151 int syncCodes = ByteBuffer.wrap(tlvs.getByteArray(CCC_SUPPORTED_SYNC_CODES)).getInt(); 152 for (int i = 0; i < 32; i++) { 153 if (isBitSet(syncCodes, 1 << i)) { 154 builder.addSyncCode(i + 1); 155 } 156 } 157 byte channels = tlvs.getByte(CCC_SUPPORTED_CHANNELS); 158 if (isBitSet(channels, CCC_CHANNEL_5)) { 159 builder.addChannel(UWB_CHANNEL_5); 160 } 161 if (isBitSet(channels, CCC_CHANNEL_9)) { 162 builder.addChannel(UWB_CHANNEL_9); 163 } 164 byte hoppingConfigModesAndSequences = 165 tlvs.getByte(CCC_SUPPORTED_HOPPING_CONFIG_MODES_AND_SEQUENCES); 166 if (isBitSet(hoppingConfigModesAndSequences, CCC_HOPPING_CONFIG_MODE_NONE)) { 167 builder.addHoppingConfigMode(HOPPING_CONFIG_MODE_NONE); 168 } 169 if (isBitSet(hoppingConfigModesAndSequences, CCC_HOPPING_CONFIG_MODE_CONTINUOUS)) { 170 builder.addHoppingConfigMode(HOPPING_CONFIG_MODE_CONTINUOUS); 171 } 172 if (isBitSet(hoppingConfigModesAndSequences, CCC_HOPPING_CONFIG_MODE_ADAPTIVE)) { 173 builder.addHoppingConfigMode(HOPPING_CONFIG_MODE_ADAPTIVE); 174 } 175 if (isBitSet(hoppingConfigModesAndSequences, CCC_HOPPING_SEQUENCE_AES)) { 176 builder.addHoppingSequence(HOPPING_SEQUENCE_AES); 177 } 178 if (isBitSet(hoppingConfigModesAndSequences, CCC_HOPPING_SEQUENCE_DEFAULT)) { 179 builder.addHoppingSequence(HOPPING_SEQUENCE_DEFAULT); 180 } 181 182 try { 183 int maxRangingSessionNumber = tlvs.getInt(CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER); 184 builder.setMaxRangingSessionNumber(maxRangingSessionNumber); 185 } catch (IllegalArgumentException e) { 186 Log.w(TAG, "SUPPORTED_MAX_RANGING_SESSION_NUMBER not found"); 187 } 188 189 try { 190 int minUwbInitiationTimeMs = tlvs.getInt(CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS); 191 builder.setMinUwbInitiationTimeMs(minUwbInitiationTimeMs); 192 } catch (IllegalArgumentException e) { 193 Log.w(TAG, "SUPPORTED_MIN_UWB_INITIATION_TIME_MS not found"); 194 } 195 return builder.build(); 196 } 197 } 198