|
|
|
/**
|
|
|
|
*
|
|
|
|
* \section COPYRIGHT
|
|
|
|
*
|
|
|
|
* Copyright 2013-2021 Software Radio Systems Limited
|
|
|
|
*
|
|
|
|
* By using this file, you agree to the terms and conditions set
|
|
|
|
* forth in the LICENSE file which can be found at the top level of
|
|
|
|
* the distribution.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef SRSENB_TA_H
|
|
|
|
#define SRSENB_TA_H
|
|
|
|
|
|
|
|
#include "srsran/config.h"
|
|
|
|
#include "srsran/phy/common/phy_common.h"
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace srsenb {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Time Aligment FSM parent/callback interface for pushing n TA values
|
|
|
|
*/
|
|
|
|
class mac_ta_ue_interface
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual uint32_t set_ta(int ta) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* UE's FSM for controlling Time Aligment command generation.
|
|
|
|
*
|
|
|
|
* Initially the FSM starts at idle state which transitions to Measure as soon as start is called. Measurements are
|
|
|
|
* collected while the FSM is in Measure state. Up to MAX_NOF_MEAS are stored. The FSM uses a minimum of MIN_NOF_MEAS
|
|
|
|
* measurements to compute the TA average. The TA command is triggered as soon as the TA average is higher than
|
|
|
|
* TA_N_THRESHOLD. After triggering a TA command, holds in prohibit state for PROHIBIT_PERIOD_MS before start collecting
|
|
|
|
* measurements.
|
|
|
|
*
|
|
|
|
* +------+ Start +---------+ Trigger +----------+
|
|
|
|
* | Idle | ------->| Measure |------------>| Prohibit |
|
|
|
|
* +------+ +---------+ +----------+
|
|
|
|
* ^ ^ |
|
|
|
|
* | | Prohibit expires |
|
|
|
|
* --+ +------------------------+
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
class ta
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
/// Control constants
|
|
|
|
static constexpr uint32_t MAX_NOF_MEAS = 16; ///< Maximum number of measurements to store
|
|
|
|
static constexpr uint32_t MIN_NOF_MEAS = 4; ///< Minimum number of measurements to compute
|
|
|
|
static constexpr uint32_t MAX_MEAS_TIME_MS = 100; ///< Maximum time of measurement
|
|
|
|
static constexpr uint32_t PROHIBIT_PERIOD_MS = 20; ///< Time to wait from the n TA value push to measure again
|
|
|
|
static constexpr int32_t TA_N_THRESHOLD = 1; ///< n TA value threshold
|
|
|
|
|
|
|
|
/// Parent/callback object
|
|
|
|
mac_ta_ue_interface* parent = nullptr;
|
|
|
|
|
|
|
|
/// TA measure datatype
|
|
|
|
typedef struct {
|
|
|
|
uint32_t ts_ms; ///< Time in which the measurement was taken in ms
|
|
|
|
float ta_us; ///< TA measurement in microseconds
|
|
|
|
} ta_meas_t;
|
|
|
|
|
|
|
|
std::mutex mutex;
|
|
|
|
|
|
|
|
uint32_t meas_t_ms = 0; ///< Time counter in milliseconds
|
|
|
|
uint32_t meas_count = 0; ///< Number of measures in the buffer
|
|
|
|
uint32_t meas_idx = 0; ///< Next mesurement index in the buffer
|
|
|
|
std::vector<ta_meas_t> meas_values;
|
|
|
|
|
|
|
|
// FSM states
|
|
|
|
typedef enum {
|
|
|
|
state_idle = 0, ///< Waits for start order
|
|
|
|
state_measure, ///< Performing measurement
|
|
|
|
state_prohibit ///< Waiting for HARQ to transmit CE command, NO measurement shall be stored
|
|
|
|
} state_t;
|
|
|
|
state_t state = state_idle;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reset Measurement and timer counter
|
|
|
|
*/
|
|
|
|
void reset_measurements()
|
|
|
|
{
|
|
|
|
meas_t_ms = 0;
|
|
|
|
meas_count = 0;
|
|
|
|
meas_idx = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Averages/extrapolates n TA value
|
|
|
|
*
|
|
|
|
* @return the required n TA value for the current time (meas_t_ms)
|
|
|
|
*/
|
|
|
|
int get_ta_n()
|
|
|
|
{
|
|
|
|
float ta_us = 0.0f;
|
|
|
|
|
|
|
|
// Average all measurements
|
|
|
|
for (uint32_t i = 0; i < meas_count; i++) {
|
|
|
|
// Write here a much fancier extrapolation algorithm
|
|
|
|
ta_us += meas_values[i].ta_us;
|
|
|
|
}
|
|
|
|
if (meas_count) {
|
|
|
|
ta_us /= static_cast<float>(meas_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the n_ta value
|
|
|
|
return static_cast<int>(std::roundf(ta_us * 1e-6f / SRSRAN_LTE_TS / 16.0f));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Runs measure state
|
|
|
|
* @return the number of enqueued MAC CE carrying TA commands
|
|
|
|
*/
|
|
|
|
uint32_t run_state_measure()
|
|
|
|
{
|
|
|
|
uint32_t ret = 0;
|
|
|
|
|
|
|
|
// Avoid processing if no measurement or no minimum covered or maximum measuring time is reached
|
|
|
|
if (meas_count == 0 or (meas_count < MIN_NOF_MEAS and meas_t_ms < MAX_MEAS_TIME_MS)) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get TA command value
|
|
|
|
int ta_n = get_ta_n();
|
|
|
|
|
|
|
|
// Send command
|
|
|
|
if (abs(ta_n) > TA_N_THRESHOLD) {
|
|
|
|
// Set UE TA
|
|
|
|
ret = parent->set_ta(ta_n);
|
|
|
|
|
|
|
|
// Reset measurement counter
|
|
|
|
reset_measurements();
|
|
|
|
|
|
|
|
// Transition to prohibit state
|
|
|
|
state = state_prohibit;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Runs prohibit state
|
|
|
|
* @return 0
|
|
|
|
*/
|
|
|
|
uint32_t run_state_prohibit()
|
|
|
|
{
|
|
|
|
// Prohibit time expired
|
|
|
|
if (meas_t_ms >= PROHIBIT_PERIOD_MS) {
|
|
|
|
// Reset counters
|
|
|
|
reset_measurements();
|
|
|
|
|
|
|
|
// Go to measure
|
|
|
|
state = state_measure;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Runs The internal FSM
|
|
|
|
* @return the number of eneuqued MAC CE carrying TA commands
|
|
|
|
*/
|
|
|
|
uint32_t run_fsm()
|
|
|
|
{
|
|
|
|
switch (state) {
|
|
|
|
case state_idle:
|
|
|
|
// Waits for Start order, do nothing
|
|
|
|
return 0;
|
|
|
|
case state_measure:
|
|
|
|
return run_state_measure();
|
|
|
|
case state_prohibit:
|
|
|
|
return run_state_prohibit();
|
|
|
|
default:; // Do nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* TA FSM Constructor
|
|
|
|
* @param parent_ UE MAC object with TA callback setter
|
|
|
|
*/
|
|
|
|
explicit ta(mac_ta_ue_interface* parent_) : parent(parent_), meas_values(MAX_NOF_MEAS)
|
|
|
|
{
|
|
|
|
/// Initial FSM run
|
|
|
|
run_fsm();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gives an start order to the FSM
|
|
|
|
*/
|
|
|
|
void start()
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
// Transition to idle only if the current state is idle
|
|
|
|
if (state == state_idle) {
|
|
|
|
state = state_measure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Pushes TA measurement and runs internal FSM
|
|
|
|
*
|
|
|
|
* @param ta_us actual TA measurement in microseconds
|
|
|
|
* @return the number of MAC CE carrying TA
|
|
|
|
*/
|
|
|
|
uint32_t push_value(float ta_us)
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
// Put measurement if state is measurement
|
|
|
|
if (state == state_measure) {
|
|
|
|
// Set measurement
|
|
|
|
meas_values[meas_idx].ts_ms = meas_t_ms;
|
|
|
|
meas_values[meas_idx].ta_us = ta_us;
|
|
|
|
|
|
|
|
// Increase pointer
|
|
|
|
meas_idx = (meas_idx + 1) % static_cast<uint32_t>(meas_values.size());
|
|
|
|
|
|
|
|
// Increase count
|
|
|
|
if (meas_count < static_cast<uint32_t>(meas_values.size())) {
|
|
|
|
meas_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run state machine
|
|
|
|
return run_fsm();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Increments internal timer 1 ms and runs internal FSM
|
|
|
|
*
|
|
|
|
* @param ta_us actual TA measurement in microseconds
|
|
|
|
* @return the number of MAC CE carrying TA
|
|
|
|
*/
|
|
|
|
uint32_t tick()
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
// Increase measurement timestamp counter
|
|
|
|
meas_t_ms++;
|
|
|
|
|
|
|
|
// Run state machine
|
|
|
|
return run_fsm();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace srsenb
|
|
|
|
|
|
|
|
#endif // SRSENB_TA_H
|