/* * 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.modules.utils.build.SdkLevel; import com.android.server.uwb.UwbInjector; 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.base.ProtocolVersion; import com.google.uwb.support.fira.FiraOpenSessionParams; import com.google.uwb.support.fira.FiraParams; import com.google.uwb.support.fira.FiraProtocolVersion; import com.google.uwb.support.fira.FiraRangingReconfigureParams; import java.nio.ByteBuffer; import java.util.Arrays; public class FiraEncoder extends TlvEncoder { private final UwbInjector mUwbInjector; public FiraEncoder(UwbInjector uwbInjector) { mUwbInjector = uwbInjector; } @Override public TlvBuffer getTlvBuffer(Params param, ProtocolVersion protocolVersion) { // The "protocolVersion" is always expected to be of type "FiraProtocolVersion" here, but // in case it's not, we use a backup value of "PROTOCOL_VERSION_1_1". FiraProtocolVersion uwbsFiraProtocolVersion = (protocolVersion instanceof FiraProtocolVersion) ? (FiraProtocolVersion) protocolVersion : FiraParams.PROTOCOL_VERSION_1_1; if (param instanceof FiraOpenSessionParams) { return getTlvBufferFromFiraOpenSessionParams(param, uwbsFiraProtocolVersion); } 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, FiraProtocolVersion uwbsFiraProtocolVersion) { FiraOpenSessionParams params = (FiraOpenSessionParams) baseParam; int deviceType = params.getDeviceType(); int resultReportConfig = getResultReportConfig(params); int rangingRoundControl = getRangingRoundControl(params); int deviceRole = params.getDeviceRole(); TlvBuffer.Builder tlvBufferBuilder = new TlvBuffer.Builder() .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()) .putByteArray(ConfigParam.DEVICE_MAC_ADDRESS, params.getDeviceAddress().size(), getComputedMacAddress(params.getDeviceAddress())) .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) params.getRangingTimeStruct()) .putByte(ConfigParam.SLOTS_PER_RR, (byte) params.getSlotsPerRangingRound()) .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()) .putShort(ConfigParam.MAX_NUMBER_OF_MEASUREMENTS, (short) params.getMaxNumberOfMeasurements()) .putByte(ConfigParam.STS_LENGTH, (byte) params.getStsLength()); if (params.getDeviceRole() != FiraParams.RANGING_DEVICE_UT_TAG) { tlvBufferBuilder.putInt(ConfigParam.RANGING_INTERVAL, params.getRangingIntervalMs()); } if (deviceRole != FiraParams.RANGING_DEVICE_DT_TAG) { tlvBufferBuilder.putByte(ConfigParam.DEVICE_TYPE, (byte) params.getDeviceType()); } if (isTimeScheduledTwrSession( params.getScheduledMode(), params.getRangingRoundUsage())) { if (params.getDestAddressList().size() > 0) { ByteBuffer dstAddressList = ByteBuffer.allocate(1024); for (UwbAddress address : params.getDestAddressList()) { dstAddressList.put(getComputedMacAddress(address)); } tlvBufferBuilder .putByte(ConfigParam.NUMBER_OF_CONTROLEES, (byte) params.getDestAddressList().size()) .putByteArray( ConfigParam.DST_MAC_ADDRESS, dstAddressList.position(), Arrays.copyOf(dstAddressList.array(), dstAddressList.position())); } } if (uwbsFiraProtocolVersion.getMajor() >= 2) { // Initiation time Changed from 4 byte field to 8 byte field in version 2. if (deviceRole != FiraParams.RANGING_DEVICE_DT_TAG) { // For FiRa 2.0+ device, prefer to set the Absolute UWB Initiation time. if (params.getAbsoluteInitiationTime() > 0) { tlvBufferBuilder.putLong(ConfigParam.UWB_INITIATION_TIME, params.getAbsoluteInitiationTime()); } else { tlvBufferBuilder.putLong(ConfigParam.UWB_INITIATION_TIME, params.getInitiationTime()); } } else { tlvBufferBuilder.putByte(ConfigParam.DL_TDOA_BLOCK_STRIDING, (byte) params.getDlTdoaBlockStriding()); } tlvBufferBuilder.putByte(ConfigParam.LINK_LAYER_MODE, (byte) params.getLinkLayerMode()) .putByte(ConfigParam.DATA_REPETITION_COUNT, (byte) params.getDataRepetitionCount()) .putByte(ConfigParam.SESSION_DATA_TRANSFER_STATUS_NTF_CONFIG, params.getSessionDataTransferStatusNtfConfig() ? (byte) 1 : (byte) 0) .putByte(ConfigParam.APPLICATION_DATA_ENDPOINT, (byte) params.getApplicationDataEndpoint()); if (deviceType == FiraParams.RANGING_DEVICE_TYPE_CONTROLLER && UwbUtil.isBitSet( params.getReferenceTimeBase(), FiraParams.SESSION_TIME_BASE_REFERENCE_FEATURE_ENABLED)) { tlvBufferBuilder.putByteArray(ConfigParam.SESSION_TIME_BASE, getSessionTimeBase(params)); } } else { if (deviceRole != FiraParams.RANGING_DEVICE_DT_TAG) { tlvBufferBuilder .putInt(ConfigParam.UWB_INITIATION_TIME, Math.toIntExact(params.getInitiationTime())); } tlvBufferBuilder.putByte(ConfigParam.TX_ADAPTIVE_PAYLOAD_POWER, params.isTxAdaptivePayloadPowerEnabled() ? (byte) 1 : (byte) 0); } configureStsParameters(tlvBufferBuilder, params); 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); if (SdkLevel.isAtLeastU()) { // Fixed bug to be compliant with HAL interface. tlvBufferBuilder.putByte(ConfigParam.ENABLE_DIAGRAMS_FRAME_REPORTS_FIELDS, params.getDiagramsFrameReportsFieldsFlags()); } else { 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()); } if (mUwbInjector.getDeviceConfigFacade().isAntennaModeConfigSupported()) { tlvBufferBuilder.putByte(ConfigParam.ANTENNA_MODE, params.getAntennaMode()); } return tlvBufferBuilder.build(); } private boolean isTimeScheduledTwrSession(int scheduledMode, int rangingUsage) { if (scheduledMode == FiraParams.TIME_SCHEDULED_RANGING) { if (rangingUsage == FiraParams.RANGING_ROUND_USAGE_SS_TWR_DEFERRED_MODE || rangingUsage == FiraParams.RANGING_ROUND_USAGE_DS_TWR_DEFERRED_MODE || rangingUsage == FiraParams.RANGING_ROUND_USAGE_SS_TWR_NON_DEFERRED_MODE || rangingUsage == FiraParams.RANGING_ROUND_USAGE_DS_TWR_NON_DEFERRED_MODE) { return true; } } return false; } private void configureStsParameters(TlvBuffer.Builder tlvBufferBuilder, FiraOpenSessionParams params) { int stsConfig = params.getStsConfig(); if (stsConfig == FiraParams.STS_CONFIG_STATIC) { tlvBufferBuilder .putByteArray(ConfigParam.VENDOR_ID, params.getVendorId() != null ? getComputedVendorId(params.getVendorId()): null) .putByteArray(ConfigParam.STATIC_STS_IV, params.getStaticStsIV()); } else if (stsConfig == FiraParams.STS_CONFIG_DYNAMIC_FOR_CONTROLEE_INDIVIDUAL_KEY) { if (params.getDeviceType() == FiraParams.RANGING_DEVICE_TYPE_CONTROLEE) { tlvBufferBuilder.putInt(ConfigParam.SUB_SESSION_ID, params.getSubSessionId()); } } else if (stsConfig == FiraParams.STS_CONFIG_PROVISIONED) { if (params.getSessionKey() != null ) { tlvBufferBuilder.putByteArray(ConfigParam.SESSION_KEY, params.getSessionKey()); } } else if (stsConfig == FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY) { if (params.getDeviceType() == FiraParams.RANGING_DEVICE_TYPE_CONTROLEE) { tlvBufferBuilder.putInt(ConfigParam.SUB_SESSION_ID, params.getSubSessionId()); if (params.getSubsessionKey() != null ) { tlvBufferBuilder. putByteArray(ConfigParam.SUBSESSION_KEY, params.getSubsessionKey()); } } if (params.getSessionKey() != null ) { tlvBufferBuilder.putByteArray(ConfigParam.SESSION_KEY, params.getSessionKey()); } } } 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(); Integer suspendRangingRounds = params.getSuspendRangingRounds(); 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), }); } } if (suspendRangingRounds != null) { tlvBuilder.putByte(ConfigParam.SUSPEND_RANGING_ROUNDS, (byte) suspendRangingRounds.intValue()); } 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); // b6 : Measurement Report Message if (params.getScheduledMode() == FiraParams.CONTENTION_BASED_RANGING) { if (params.getMeasurementReportPhase() == FiraParams.MEASUREMENT_REPORT_PHASE_SET) { rangingRoundControl |= (byte) 0x40; } } // b7 : Measurement Report Message if (params.getMeasurementReportType() == FiraParams.MEASUREMENT_REPORT_TYPE_RESPONDER_TO_INITIATOR) { rangingRoundControl |= (byte) 0x80; } return rangingRoundControl; } private static byte[] getComputedMacAddress(UwbAddress address) { if (!SdkLevel.isAtLeastU()) { return TlvUtil.getReverseBytes(address.toBytes()); } return address.toBytes(); } private static byte[] getComputedVendorId(byte[] data) { if (!SdkLevel.isAtLeastU()) { return TlvUtil.getReverseBytes(data); } return data; } private byte[] getSessionTimeBase(FiraOpenSessionParams params) { byte[] sessionTimeBaseParam = new byte[FiraParams.SESSION_TIME_BASE_PARAM_LEN]; int offset = 0; sessionTimeBaseParam[offset++] = (byte) params.getReferenceTimeBase(); byte[] sessionHandleValue = TlvUtil.getBytes(params.getReferenceSessionHandle()); for (int index = FiraParams.SESSION_HANDLE_LEN - 1; index >= 0; index--) { sessionTimeBaseParam[offset++] = (byte) sessionHandleValue[index]; } byte[] sessionOffsetInMicroSecondValue = TlvUtil.getBytes(params.getSessionOffsetInMicroSeconds()); for (int index = FiraParams.SESSION_OFFSET_TIME_LEN - 1; index >= 0; index--) { sessionTimeBaseParam[offset++] = (byte) sessionOffsetInMicroSecondValue[index]; } return sessionTimeBaseParam; } }