blob: 6f1eb5616241e5a26f05a5fdf201124ed4e61476 [file] [log] [blame]
/*
* 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.android.server.uwb.params;
import static com.android.server.uwb.config.CapabilityParam.CCC_CHANNEL_5;
import static com.android.server.uwb.config.CapabilityParam.CCC_CHANNEL_9;
import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_12;
import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_24;
import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_3;
import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_4;
import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_6;
import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_8;
import static com.android.server.uwb.config.CapabilityParam.CCC_CHAPS_PER_SLOT_9;
import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_CONFIG_MODE_ADAPTIVE;
import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_CONFIG_MODE_CONTINUOUS;
import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_CONFIG_MODE_NONE;
import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_SEQUENCE_AES;
import static com.android.server.uwb.config.CapabilityParam.CCC_HOPPING_SEQUENCE_DEFAULT;
import static com.android.server.uwb.config.CapabilityParam.CCC_PRIORITIZED_CHANNEL_LIST;
import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_CHANNELS;
import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_CHAPS_PER_SLOT;
import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_HOPPING_CONFIG_MODES_AND_SEQUENCES;
import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER;
import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS;
import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_PULSE_SHAPE_COMBOS;
import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_RAN_MULTIPLIER;
import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_SYNC_CODES;
import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_UWB_CONFIGS;
import static com.android.server.uwb.config.CapabilityParam.CCC_SUPPORTED_VERSIONS;
import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_12;
import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_24;
import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_3;
import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_4;
import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_6;
import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_8;
import static com.google.uwb.support.ccc.CccParams.CHAPS_PER_SLOT_9;
import static com.google.uwb.support.ccc.CccParams.HOPPING_CONFIG_MODE_ADAPTIVE;
import static com.google.uwb.support.ccc.CccParams.HOPPING_CONFIG_MODE_CONTINUOUS;
import static com.google.uwb.support.ccc.CccParams.HOPPING_CONFIG_MODE_NONE;
import static com.google.uwb.support.ccc.CccParams.HOPPING_SEQUENCE_AES;
import static com.google.uwb.support.ccc.CccParams.HOPPING_SEQUENCE_DEFAULT;
import static com.google.uwb.support.ccc.CccParams.UWB_CHANNEL_5;
import static com.google.uwb.support.ccc.CccParams.UWB_CHANNEL_9;
import android.util.Log;
import com.android.server.uwb.UwbInjector;
import com.android.server.uwb.config.ConfigParam;
import com.google.uwb.support.base.Params;
import com.google.uwb.support.base.ProtocolVersion;
import com.google.uwb.support.ccc.CccProtocolVersion;
import com.google.uwb.support.ccc.CccPulseShapeCombo;
import com.google.uwb.support.ccc.CccRangingStartedParams;
import com.google.uwb.support.ccc.CccRangingStoppedParams;
import com.google.uwb.support.ccc.CccSpecificationParams;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* CCC decoder
*/
public class CccDecoder extends TlvDecoder {
private static final String TAG = "CccDecoder";
private final UwbInjector mUwbInjector;
public CccDecoder(UwbInjector uwbInjector) {
mUwbInjector = uwbInjector;
}
@Override
public <T extends Params> T getParams(TlvDecoderBuffer tlvs, Class<T> paramsType,
ProtocolVersion protocolVersion)
throws IllegalArgumentException {
if (CccRangingStartedParams.class.equals(paramsType)) {
return (T) getCccRangingStartedParamsFromTlvBuffer(tlvs);
}
if (CccSpecificationParams.class.equals(paramsType)) {
return (T) getCccSpecificationParamsFromTlvBuffer(tlvs);
}
if (CccRangingStoppedParams.class.equals(paramsType)) {
return (T) getCccRangingStoppedParamsFromTlvBuffer(tlvs);
}
return null;
}
private static boolean isBitSet(int flags, int mask) {
return (flags & mask) != 0;
}
private CccRangingStartedParams getCccRangingStartedParamsFromTlvBuffer(TlvDecoderBuffer tlvs) {
byte[] hopModeKey = tlvs.getByteArray(ConfigParam.HOP_MODE_KEY);
int hopModeKeyInt = ByteBuffer.wrap(hopModeKey).order(ByteOrder.LITTLE_ENDIAN).getInt();
long uwbTime0;
// Backwards compatibility with vendors who were using Google defined
// UWB_TIME0 TLV param.
try {
uwbTime0 = tlvs.getLong(ConfigParam.UWB_TIME0);
} catch (IllegalArgumentException e) {
uwbTime0 = tlvs.getLong(ConfigParam.UWB_INITIATION_TIME);
}
return new CccRangingStartedParams.Builder()
// STS_Index0 0 - 0x3FFFFFFFF
.setStartingStsIndex(tlvs.getInt(ConfigParam.STS_INDEX))
.setHopModeKey(hopModeKeyInt)
// UWB_Time0 0 - 0xFFFFFFFFFFFFFFFF UWB_INITIATION_TIME
.setUwbTime0(uwbTime0)
// RANGING_INTERVAL = RAN_Multiplier * 96
.setRanMultiplier(tlvs.getInt(ConfigParam.RANGING_INTERVAL) / 96)
.setSyncCodeIndex(tlvs.getByte(ConfigParam.PREAMBLE_CODE_INDEX))
.build();
}
private CccSpecificationParams getCccSpecificationParamsFromTlvBuffer(TlvDecoderBuffer tlvs) {
CccSpecificationParams.Builder builder = new CccSpecificationParams.Builder();
byte[] versions = tlvs.getByteArray(CCC_SUPPORTED_VERSIONS);
if (versions.length % 2 != 0) {
throw new IllegalArgumentException("Invalid supported protocol versions len "
+ versions.length);
}
for (int i = 0; i < versions.length; i += 2) {
builder.addProtocolVersion(CccProtocolVersion.fromBytes(versions, i));
}
byte[] configs = tlvs.getByteArray(CCC_SUPPORTED_UWB_CONFIGS);
for (int i = 0; i < configs.length; i++) {
builder.addUwbConfig(configs[i]);
}
byte[] pulse_shape_combos = tlvs.getByteArray(CCC_SUPPORTED_PULSE_SHAPE_COMBOS);
for (int i = 0; i < pulse_shape_combos.length; i++) {
builder.addPulseShapeCombo(CccPulseShapeCombo.fromBytes(pulse_shape_combos, i));
}
builder.setRanMultiplier(tlvs.getInt(CCC_SUPPORTED_RAN_MULTIPLIER));
byte chapsPerslot = tlvs.getByte(CCC_SUPPORTED_CHAPS_PER_SLOT);
if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_3)) {
builder.addChapsPerSlot(CHAPS_PER_SLOT_3);
}
if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_4)) {
builder.addChapsPerSlot(CHAPS_PER_SLOT_4);
}
if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_6)) {
builder.addChapsPerSlot(CHAPS_PER_SLOT_6);
}
if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_8)) {
builder.addChapsPerSlot(CHAPS_PER_SLOT_8);
}
if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_9)) {
builder.addChapsPerSlot(CHAPS_PER_SLOT_9);
}
if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_12)) {
builder.addChapsPerSlot(CHAPS_PER_SLOT_12);
}
if (isBitSet(chapsPerslot, CCC_CHAPS_PER_SLOT_24)) {
builder.addChapsPerSlot(CHAPS_PER_SLOT_24);
}
if (mUwbInjector.getDeviceConfigFacade().isCccSupportedSyncCodesLittleEndian()) {
byte[] syncCodes = tlvs.getByteArray(CCC_SUPPORTED_SYNC_CODES);
for (int byteIndex = 0; byteIndex < syncCodes.length; byteIndex++) {
byte syncCodeByte = syncCodes[byteIndex];
for (int bitIndex = 0; bitIndex < 8; bitIndex++) {
if ((syncCodeByte & (1 << bitIndex)) != 0) {
int syncCodeValue = (byteIndex * 8) + bitIndex + 1;
builder.addSyncCode(syncCodeValue);
}
}
}
} else {
int syncCodes = ByteBuffer.wrap(tlvs.getByteArray(CCC_SUPPORTED_SYNC_CODES)).getInt();
for (int i = 0; i < 32; i++) {
if (isBitSet(syncCodes, 1 << i)) {
builder.addSyncCode(i + 1);
}
}
}
try {
byte[] prioritizedChannels = tlvs.getByteArray(CCC_PRIORITIZED_CHANNEL_LIST);
for (byte prioritizedChannel : prioritizedChannels) {
builder.addChannel(prioritizedChannel);
}
} catch (IllegalArgumentException e) {
Log.w(TAG, "CCC_PRIORITIZED_CHANNEL_LIST not found");
byte channels = tlvs.getByte(CCC_SUPPORTED_CHANNELS);
if (isBitSet(channels, CCC_CHANNEL_5)) {
builder.addChannel(UWB_CHANNEL_5);
}
if (isBitSet(channels, CCC_CHANNEL_9)) {
builder.addChannel(UWB_CHANNEL_9);
}
}
byte hoppingConfigModesAndSequences =
tlvs.getByte(CCC_SUPPORTED_HOPPING_CONFIG_MODES_AND_SEQUENCES);
if (isBitSet(hoppingConfigModesAndSequences, CCC_HOPPING_CONFIG_MODE_NONE)) {
builder.addHoppingConfigMode(HOPPING_CONFIG_MODE_NONE);
}
if (isBitSet(hoppingConfigModesAndSequences, CCC_HOPPING_CONFIG_MODE_CONTINUOUS)) {
builder.addHoppingConfigMode(HOPPING_CONFIG_MODE_CONTINUOUS);
}
if (isBitSet(hoppingConfigModesAndSequences, CCC_HOPPING_CONFIG_MODE_ADAPTIVE)) {
builder.addHoppingConfigMode(HOPPING_CONFIG_MODE_ADAPTIVE);
}
if (isBitSet(hoppingConfigModesAndSequences, CCC_HOPPING_SEQUENCE_AES)) {
builder.addHoppingSequence(HOPPING_SEQUENCE_AES);
}
if (isBitSet(hoppingConfigModesAndSequences, CCC_HOPPING_SEQUENCE_DEFAULT)) {
builder.addHoppingSequence(HOPPING_SEQUENCE_DEFAULT);
}
try {
int maxRangingSessionNumber = tlvs.getInt(CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER);
builder.setMaxRangingSessionNumber(maxRangingSessionNumber);
} catch (IllegalArgumentException e) {
Log.w(TAG, "SUPPORTED_MAX_RANGING_SESSION_NUMBER not found");
}
try {
int minUwbInitiationTimeMs = tlvs.getInt(CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS);
builder.setMinUwbInitiationTimeMs(minUwbInitiationTimeMs);
} catch (IllegalArgumentException e) {
Log.w(TAG, "SUPPORTED_MIN_UWB_INITIATION_TIME_MS not found");
}
return builder.build();
}
private CccRangingStoppedParams getCccRangingStoppedParamsFromTlvBuffer(TlvDecoderBuffer tlvs) {
int lastStsIndexUsed = tlvs.getInt(ConfigParam.LAST_STS_INDEX_USED);
return new CccRangingStoppedParams.Builder()
.setLastStsIndexUsed(lastStsIndexUsed)
.build();
}
}