blob: b74a38da4353e8f4ec086b4b6cf1f20a167e32cb [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.google.uwb.support.fira.FiraParams.RANGE_DATA_NTF_CONFIG_ENABLE_AOA_EDGE_TRIG;
import static com.google.uwb.support.fira.FiraParams.RANGE_DATA_NTF_CONFIG_ENABLE_AOA_LEVEL_TRIG;
import static com.google.uwb.support.fira.FiraParams.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_EDGE_TRIG;
import static com.google.uwb.support.fira.FiraParams.RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_LEVEL_TRIG;
import android.uwb.UwbAddress;
import com.android.server.uwb.config.ConfigParam;
import com.android.server.uwb.util.UwbUtil;
import com.google.uwb.support.base.Params;
import com.google.uwb.support.fira.FiraOpenSessionParams;
import com.google.uwb.support.fira.FiraParams;
import com.google.uwb.support.fira.FiraRangingReconfigureParams;
import java.nio.ByteBuffer;
import java.util.Arrays;
public class FiraEncoder extends TlvEncoder {
@Override
public TlvBuffer getTlvBuffer(Params param) {
if (param instanceof FiraOpenSessionParams) {
return getTlvBufferFromFiraOpenSessionParams(param);
}
if (param instanceof FiraRangingReconfigureParams) {
return getTlvBufferFromFiraRangingReconfigureParams(param);
}
return null;
}
private static boolean hasAoaBoundInRangeDataNtfConfig(int rangeDataNtfConfig) {
return rangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_AOA_LEVEL_TRIG
|| rangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_LEVEL_TRIG
|| rangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_AOA_EDGE_TRIG
|| rangeDataNtfConfig == RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY_AOA_EDGE_TRIG;
}
private TlvBuffer getTlvBufferFromFiraOpenSessionParams(Params baseParam) {
FiraOpenSessionParams params = (FiraOpenSessionParams) baseParam;
ByteBuffer dstAddressList = ByteBuffer.allocate(1024);
for (UwbAddress address : params.getDestAddressList()) {
dstAddressList.put(TlvUtil.getReverseBytes(address.toBytes()));
}
int stsConfig = params.getStsConfig();
int deviceType = params.getDeviceType();
int resultReportConfig = getResultReportConfig(params);
int rangingRoundControl = getRangingRoundControl(params);
TlvBuffer.Builder tlvBufferBuilder = new TlvBuffer.Builder()
.putByte(ConfigParam.DEVICE_TYPE, (byte) params.getDeviceType())
.putByte(ConfigParam.RANGING_ROUND_USAGE, (byte) params.getRangingRoundUsage())
.putByte(ConfigParam.STS_CONFIG, (byte) params.getStsConfig())
.putByte(ConfigParam.MULTI_NODE_MODE, (byte) params.getMultiNodeMode())
.putByte(ConfigParam.CHANNEL_NUMBER, (byte) params.getChannelNumber())
.putByte(ConfigParam.NUMBER_OF_CONTROLEES,
(byte) params.getDestAddressList().size())
.putByteArray(ConfigParam.DEVICE_MAC_ADDRESS, params.getDeviceAddress().size(),
TlvUtil.getReverseBytes(params.getDeviceAddress().toBytes()))
.putShort(ConfigParam.SLOT_DURATION, (short) params.getSlotDurationRstu())
.putByte(ConfigParam.MAC_FCS_TYPE, (byte) params.getFcsType())
.putByte(ConfigParam.RANGING_ROUND_CONTROL,
(byte) rangingRoundControl/* params.getMeasurementReportType()*/)
.putByte(ConfigParam.AOA_RESULT_REQ, (byte) params.getAoaResultRequest())
.putByte(ConfigParam.RANGE_DATA_NTF_CONFIG, (byte) params.getRangeDataNtfConfig())
.putShort(ConfigParam.RANGE_DATA_NTF_PROXIMITY_NEAR,
(short) params.getRangeDataNtfProximityNear())
.putShort(ConfigParam.RANGE_DATA_NTF_PROXIMITY_FAR,
(short) params.getRangeDataNtfProximityFar())
.putByte(ConfigParam.DEVICE_ROLE, (byte) params.getDeviceRole())
.putByte(ConfigParam.RFRAME_CONFIG, (byte) params.getRframeConfig())
.putByte(ConfigParam.RSSI_REPORTING,
(byte) (params.isRssiReportingEnabled() ? 1 : 0))
.putByte(ConfigParam.PREAMBLE_CODE_INDEX, (byte) params.getPreambleCodeIndex())
.putByte(ConfigParam.SFD_ID, (byte) params.getSfdId())
.putByte(ConfigParam.PSDU_DATA_RATE, (byte) params.getPsduDataRate())
.putByte(ConfigParam.PREAMBLE_DURATION, (byte) params.getPreambleDuration())
// n.a. for OWR UL-TDoA and 0x01 for all other RangingRoundUsage values.
.putByte(ConfigParam.RANGING_TIME_STRUCT, (byte) 0x01)
.putByte(ConfigParam.SLOTS_PER_RR, (byte) params.getSlotsPerRangingRound())
.putByte(ConfigParam.TX_ADAPTIVE_PAYLOAD_POWER,
params.isTxAdaptivePayloadPowerEnabled() ? (byte) 1 : (byte) 0)
.putByte(ConfigParam.PRF_MODE, (byte) params.getPrfMode())
.putByte(ConfigParam.SCHEDULED_MODE, (byte) params.getScheduledMode())
.putByte(ConfigParam.KEY_ROTATION,
params.isKeyRotationEnabled() ? (byte) 1 : (byte) 0)
.putByte(ConfigParam.KEY_ROTATION_RATE, (byte) params.getKeyRotationRate())
.putByte(ConfigParam.SESSION_PRIORITY, (byte) params.getSessionPriority())
.putByte(ConfigParam.MAC_ADDRESS_MODE, (byte) params.getMacAddressMode())
.putByte(ConfigParam.NUMBER_OF_STS_SEGMENTS, (byte) params.getStsSegmentCount())
.putShort(ConfigParam.MAX_RR_RETRY, (short) params.getMaxRangingRoundRetries())
.putByte(ConfigParam.HOPPING_MODE,
(byte) params.getHoppingMode())
.putByte(ConfigParam.BLOCK_STRIDE_LENGTH, (byte) params.getBlockStrideLength())
.putByte(ConfigParam.RESULT_REPORT_CONFIG, (byte) resultReportConfig)
.putByte(ConfigParam.IN_BAND_TERMINATION_ATTEMPT_COUNT,
(byte) params.getInBandTerminationAttemptCount())
.putByte(ConfigParam.BPRF_PHR_DATA_RATE,
(byte) params.getBprfPhrDataRate())
.putByte(ConfigParam.STS_LENGTH, (byte) params.getStsLength());
if (params.getDeviceRole() != FiraParams.RANGING_DEVICE_UT_TAG) {
tlvBufferBuilder.putInt(ConfigParam.RANGING_INTERVAL, params.getRangingIntervalMs());
}
if (params.getDestAddressList().size() > 0) {
tlvBufferBuilder.putByteArray(
ConfigParam.DST_MAC_ADDRESS, dstAddressList.position(),
Arrays.copyOf(dstAddressList.array(), dstAddressList.position()));
}
if (params.getProtocolVersion().getMajor() >= 2) {
tlvBufferBuilder
// Initiation time Changed from 4 byte field to 8 byte field in version 2.
.putLong(ConfigParam.UWB_INITIATION_TIME, params.getInitiationTimeMs())
.putByte(ConfigParam.LINK_LAYER_MODE, (byte) params.getLinkLayerMode());
} else {
tlvBufferBuilder.putInt(ConfigParam.UWB_INITIATION_TIME,
Math.toIntExact(params.getInitiationTimeMs()));
}
if ((stsConfig == FiraParams.STS_CONFIG_DYNAMIC_FOR_CONTROLEE_INDIVIDUAL_KEY)
&& (deviceType == FiraParams.RANGING_DEVICE_TYPE_CONTROLEE)) {
tlvBufferBuilder.putInt(ConfigParam.SUB_SESSION_ID, params.getSubSessionId());
}
if (stsConfig == FiraParams.STS_CONFIG_STATIC) {
tlvBufferBuilder
.putByteArray(ConfigParam.VENDOR_ID, params.getVendorId() != null
? TlvUtil.getReverseBytes(params.getVendorId())
: null)
.putByteArray(ConfigParam.STATIC_STS_IV, params.getStaticStsIV());
} else if ((stsConfig == FiraParams.STS_CONFIG_PROVISIONED)
|| (stsConfig
== FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY)) {
tlvBufferBuilder.putByteArray(ConfigParam.SESSION_KEY, params.getSessionKey());
if (stsConfig
== FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY
&& (deviceType == FiraParams.RANGING_DEVICE_TYPE_CONTROLEE)) {
tlvBufferBuilder.putInt(ConfigParam.SUB_SESSION_ID, params.getSubSessionId());
tlvBufferBuilder.putByteArray(ConfigParam.SUBSESSION_KEY,
params.getSubsessionKey());
}
}
if (params.getAoaResultRequest()
== FiraParams.AOA_RESULT_REQUEST_MODE_REQ_AOA_RESULTS_INTERLEAVED) {
tlvBufferBuilder.putByte(ConfigParam.NUM_RANGE_MEASUREMENTS,
(byte) params.getNumOfMsrmtFocusOnRange())
.putByte(ConfigParam.NUM_AOA_AZIMUTH_MEASUREMENTS,
(byte) params.getNumOfMsrmtFocusOnAoaAzimuth())
.putByte(ConfigParam.NUM_AOA_ELEVATION_MEASUREMENTS,
(byte) params.getNumOfMsrmtFocusOnAoaElevation());
}
if (hasAoaBoundInRangeDataNtfConfig(params.getRangeDataNtfConfig())) {
tlvBufferBuilder.putShortArray(ConfigParam.RANGE_DATA_NTF_AOA_BOUND, new short[]{
// TODO (b/235355249): Verify this conversion. This is using AOA value
// in UwbTwoWayMeasurement to external RangingMeasurement conversion as
// reference.
(short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
UwbUtil.radianTodegree(
params.getRangeDataNtfAoaAzimuthLower()), 9, 7), 16),
(short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
UwbUtil.radianTodegree(
params.getRangeDataNtfAoaAzimuthUpper()), 9, 7), 16),
(short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
UwbUtil.radianTodegree(
params.getRangeDataNtfAoaElevationLower()), 9, 7), 16),
(short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
UwbUtil.radianTodegree(
params.getRangeDataNtfAoaElevationUpper()), 9, 7), 16),
});
}
if (params.isDiagnosticsEnabled()) {
tlvBufferBuilder.putByte(ConfigParam.ENABLE_DIAGNOSTICS_RSSI, (byte) 1);
tlvBufferBuilder.putInt(ConfigParam.ENABLE_DIAGRAMS_FRAME_REPORTS_FIELDS,
params.getDiagramsFrameReportsFieldsFlags());
}
if (params.getScheduledMode() == FiraParams.CONTENTION_BASED_RANGING) {
tlvBufferBuilder.putByteArray(ConfigParam.CAP_SIZE_RANGE, params.getCapSize());
}
if (params.getDeviceRole() == FiraParams.RANGING_DEVICE_UT_TAG) {
tlvBufferBuilder.putInt(ConfigParam.UL_TDOA_TX_INTERVAL,
params.getUlTdoaTxIntervalMs());
tlvBufferBuilder.putInt(ConfigParam.UL_TDOA_RANDOM_WINDOW,
params.getUlTdoaRandomWindowMs());
tlvBufferBuilder.putByteArray(ConfigParam.UL_TDOA_DEVICE_ID, getUlTdoaDeviceId(
params.getUlTdoaDeviceIdType(), params.getUlTdoaDeviceId()));
tlvBufferBuilder.putByte(ConfigParam.UL_TDOA_TX_TIMESTAMP,
(byte) params.getUlTdoaTxTimestampType());
}
if (params.getDeviceRole() == FiraParams.RANGING_DEVICE_ROLE_ADVERTISER ||
params.getDeviceRole() == FiraParams.RANGING_DEVICE_ROLE_OBSERVER) {
tlvBufferBuilder
.putByte(ConfigParam.MIN_FRAMES_PER_RR, (byte) params.getMinFramesPerRr())
.putShort(ConfigParam.MTU_SIZE, (short) params.getMtuSize())
.putByte(ConfigParam.INTER_FRAME_INTERVAL, (byte) params.getInterFrameInterval());
}
return tlvBufferBuilder.build();
}
private byte[] getUlTdoaDeviceId(int ulTdoaDeviceIdType, byte[] ulTdoaDeviceId) {
if (ulTdoaDeviceIdType == FiraParams.UL_TDOA_DEVICE_ID_NONE) {
// Device ID not included
return new byte[]{0};
}
ByteBuffer buffer = ByteBuffer.allocate(ulTdoaDeviceId.length + 1);
buffer.put((byte) ulTdoaDeviceIdType);
buffer.put(ulTdoaDeviceId);
return buffer.array();
}
private TlvBuffer getTlvBufferFromFiraRangingReconfigureParams(Params baseParam) {
FiraRangingReconfigureParams params = (FiraRangingReconfigureParams) baseParam;
TlvBuffer.Builder tlvBuilder = new TlvBuffer.Builder();
Integer blockStrideLength = params.getBlockStrideLength();
Integer rangeDataNtfConfig = params.getRangeDataNtfConfig();
Integer rangeDataProximityNear = params.getRangeDataProximityNear();
Integer rangeDataProximityFar = params.getRangeDataProximityFar();
Double rangeDataAoaAzimuthLower = params.getRangeDataAoaAzimuthLower();
Double rangeDataAoaAzimuthUpper = params.getRangeDataAoaAzimuthUpper();
Double rangeDataAoaElevationLower = params.getRangeDataAoaElevationLower();
Double rangeDataAoaElevationUpper = params.getRangeDataAoaElevationUpper();
if (blockStrideLength != null) {
tlvBuilder.putByte(ConfigParam.BLOCK_STRIDE_LENGTH,
(byte) blockStrideLength.intValue());
}
if (rangeDataNtfConfig != null) {
tlvBuilder.putByte(ConfigParam.RANGE_DATA_NTF_CONFIG,
(byte) rangeDataNtfConfig.intValue());
}
if (rangeDataProximityNear != null) {
tlvBuilder.putShort(ConfigParam.RANGE_DATA_NTF_PROXIMITY_NEAR,
(short) rangeDataProximityNear.intValue());
}
if (rangeDataProximityFar != null) {
tlvBuilder.putShort(ConfigParam.RANGE_DATA_NTF_PROXIMITY_FAR,
(short) rangeDataProximityFar.intValue());
}
if (rangeDataNtfConfig != null && hasAoaBoundInRangeDataNtfConfig(rangeDataNtfConfig)) {
if ((rangeDataAoaAzimuthLower != null && rangeDataAoaAzimuthUpper != null)
|| (rangeDataAoaElevationLower != null && rangeDataAoaElevationUpper != null)) {
rangeDataAoaAzimuthLower = rangeDataAoaAzimuthLower != null
? rangeDataAoaAzimuthLower
: FiraParams.RANGE_DATA_NTF_AOA_AZIMUTH_LOWER_DEFAULT;
rangeDataAoaAzimuthUpper = rangeDataAoaAzimuthUpper != null
? rangeDataAoaAzimuthUpper
: FiraParams.RANGE_DATA_NTF_AOA_AZIMUTH_UPPER_DEFAULT;
rangeDataAoaElevationLower = rangeDataAoaElevationLower != null
? rangeDataAoaElevationLower
: FiraParams.RANGE_DATA_NTF_AOA_ELEVATION_LOWER_DEFAULT;
rangeDataAoaElevationUpper = rangeDataAoaElevationUpper != null
? rangeDataAoaElevationUpper
: FiraParams.RANGE_DATA_NTF_AOA_ELEVATION_UPPER_DEFAULT;
tlvBuilder.putShortArray(ConfigParam.RANGE_DATA_NTF_AOA_BOUND, new short[]{
// TODO (b/235355249): Verify this conversion. This is using AOA value
// in UwbTwoWayMeasurement to external RangingMeasurement conversion as
// reference.
(short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
UwbUtil.radianTodegree(
rangeDataAoaAzimuthLower.floatValue()), 9, 7), 16),
(short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
UwbUtil.radianTodegree(
rangeDataAoaAzimuthUpper.floatValue()), 9, 7), 16),
(short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
UwbUtil.radianTodegree(
rangeDataAoaElevationLower.floatValue()), 9, 7), 16),
(short) UwbUtil.twos_compliment(UwbUtil.convertFloatToQFormat(
UwbUtil.radianTodegree(
rangeDataAoaElevationUpper.floatValue()), 9, 7), 16),
});
}
}
return tlvBuilder.build();
}
// Merged data from other parameter values
private int getResultReportConfig(FiraOpenSessionParams params) {
int resultReportConfig = 0x00;
resultReportConfig |= params.hasTimeOfFlightReport() ? 0x01 : 0x00;
resultReportConfig |= params.hasAngleOfArrivalAzimuthReport() ? 0x02 : 0x00;
resultReportConfig |= params.hasAngleOfArrivalElevationReport() ? 0x04 : 0x00;
resultReportConfig |= params.hasAngleOfArrivalFigureOfMeritReport() ? 0x08 : 0x00;
return resultReportConfig;
}
private int getRangingRoundControl(FiraOpenSessionParams params) {
// RANGING_ROUND_CONTROL
byte rangingRoundControl = 0x00;
// b0 : Ranging Result Report Message
rangingRoundControl |= (byte) (params.hasRangingResultReportMessage() ? 0x01 : 0x00);
// b1 : Control Message
rangingRoundControl |= (byte) (params.hasControlMessage() ? 0x02 : 0x00);
// b2 : Ranging Control Phase
rangingRoundControl |= (byte) (params.hasRangingControlPhase() ? 0x04 : 0x00);
// b7 : Measurement Report Message
if (params.getMeasurementReportType()
== FiraParams.MEASUREMENT_REPORT_TYPE_RESPONDER_TO_INITIATOR) {
rangingRoundControl |= 0x80;
}
return rangingRoundControl;
}
}