mirror of https://github.com/pvnis/srsRAN_4G.git
Initial UE NR SA PHY classes
parent
cfa614226e
commit
b1bcc1a8c0
@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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 SRSUE_CELL_SEARCH_H
|
||||||
|
#define SRSUE_CELL_SEARCH_H
|
||||||
|
|
||||||
|
#include "srsran/interfaces/radio_interfaces.h"
|
||||||
|
#include "srsran/interfaces/ue_nr_interfaces.h"
|
||||||
|
#include "srsran/srsran.h"
|
||||||
|
|
||||||
|
namespace srsue {
|
||||||
|
namespace nr {
|
||||||
|
class cell_search
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct args_t {
|
||||||
|
double max_srate_hz;
|
||||||
|
srsran_subcarrier_spacing_t ssb_min_scs = srsran_subcarrier_spacing_15kHz;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cfg_t {
|
||||||
|
double srate_hz;
|
||||||
|
double center_freq_hz;
|
||||||
|
double ssb_freq_hz;
|
||||||
|
srsran_subcarrier_spacing_t ssb_scs;
|
||||||
|
srsran_ssb_patern_t ssb_pattern;
|
||||||
|
srsran_duplex_mode_t duplex_mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
cell_search(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_);
|
||||||
|
|
||||||
|
~cell_search();
|
||||||
|
|
||||||
|
bool init(const args_t& args);
|
||||||
|
|
||||||
|
bool start(const cfg_t& cfg);
|
||||||
|
|
||||||
|
bool run();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
srslog::basic_logger& logger;
|
||||||
|
stack_interface_phy_sa_nr& stack;
|
||||||
|
srsran::radio_interface_phy& radio;
|
||||||
|
srsran_ssb_t ssb = {};
|
||||||
|
uint32_t sf_sz = 0; ///< subframe size in samples (1 ms)
|
||||||
|
cf_t* buffer = nullptr; ///< Receive buffer
|
||||||
|
};
|
||||||
|
} // namespace nr
|
||||||
|
} // namespace srsue
|
||||||
|
|
||||||
|
#endif // SRSUE_CELL_SEARCH_H
|
@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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 SRSUE_SLOT_SYNC_H
|
||||||
|
#define SRSUE_SLOT_SYNC_H
|
||||||
|
|
||||||
|
#include "srsran/interfaces/radio_interfaces.h"
|
||||||
|
#include "srsran/interfaces/ue_nr_interfaces.h"
|
||||||
|
#include "srsran/radio/rf_buffer.h"
|
||||||
|
#include "srsran/radio/rf_timestamp.h"
|
||||||
|
#include "srsran/srsran.h"
|
||||||
|
|
||||||
|
namespace srsue {
|
||||||
|
namespace nr {
|
||||||
|
class slot_sync
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct args_t {
|
||||||
|
double max_srate_hz = 1.92e6;
|
||||||
|
uint32_t nof_rx_channels = 1;
|
||||||
|
srsran_subcarrier_spacing_t ssb_min_scs = srsran_subcarrier_spacing_15kHz;
|
||||||
|
bool disable_cfo = false;
|
||||||
|
float pbch_dmrs_thr = 0.0f; ///< PBCH DMRS correlation detection threshold (0 means auto)
|
||||||
|
float cfo_alpha = 0.0f; ///< CFO averaging alpha (0 means auto)
|
||||||
|
int thread_priority = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
slot_sync(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_);
|
||||||
|
~slot_sync();
|
||||||
|
|
||||||
|
bool init(const args_t& args);
|
||||||
|
|
||||||
|
int recv_callback(srsran::rf_buffer_t& rf_buffer, srsran_timestamp_t* timestamp);
|
||||||
|
void run_stack_tti();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const static int MIN_TTI_JUMP = 1; ///< Time gap reported to stack after receiving subframe
|
||||||
|
const static int MAX_TTI_JUMP = 1000; ///< Maximum time gap tolerance in RF stream metadata
|
||||||
|
enum { SEARCHING = 0, CAMPING } state = SEARCHING;
|
||||||
|
srslog::basic_logger& logger;
|
||||||
|
stack_interface_phy_sa_nr& stack;
|
||||||
|
srsran::radio_interface_phy& radio;
|
||||||
|
srsran_ue_sync_nr_t ue_sync_nr = {};
|
||||||
|
srsran::rf_timestamp_t last_rx_time;
|
||||||
|
srsran_timestamp_t stack_tti_ts_new = {};
|
||||||
|
srsran_timestamp_t stack_tti_ts = {};
|
||||||
|
bool forced_rx_time_init = true; // Rx time sync after first receive from radio
|
||||||
|
uint32_t tti = 0;
|
||||||
|
};
|
||||||
|
} // namespace nr
|
||||||
|
} // namespace srsue
|
||||||
|
|
||||||
|
#endif // SRSUE_SLOT_SYNC_H
|
@ -0,0 +1,117 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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 SRSUE_SYNC_NR_SA_H
|
||||||
|
#define SRSUE_SYNC_NR_SA_H
|
||||||
|
|
||||||
|
#include "cell_search.h"
|
||||||
|
#include "slot_sync.h"
|
||||||
|
#include "srsran/common/threads.h"
|
||||||
|
#include "srsran/interfaces/radio_interfaces.h"
|
||||||
|
#include "srsran/interfaces/ue_nr_interfaces.h"
|
||||||
|
#include "srsran/radio/rf_buffer.h"
|
||||||
|
#include "srsran/radio/rf_timestamp.h"
|
||||||
|
#include "srsran/srslog/logger.h"
|
||||||
|
#include "srsran/srsran.h"
|
||||||
|
#include "worker_pool.h"
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
#include <srsran/common/tti_sempahore.h>
|
||||||
|
|
||||||
|
namespace srsue {
|
||||||
|
namespace nr {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief NR Standalone synchronization class
|
||||||
|
*/
|
||||||
|
class sync_sa : public srsran::thread, public srsran::phy_common_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct args_t {
|
||||||
|
double srate_hz = 61.44e6;
|
||||||
|
srsran_subcarrier_spacing_t ssb_min_scs = srsran_subcarrier_spacing_15kHz;
|
||||||
|
uint32_t nof_rx_channels = 1;
|
||||||
|
bool disable_cfo = false;
|
||||||
|
float pbch_dmrs_thr = 0.0f; ///< PBCH DMRS correlation detection threshold (0 means auto)
|
||||||
|
float cfo_alpha = 0.0f; ///< CFO averaging alpha (0 means auto)
|
||||||
|
int thread_priority = -1;
|
||||||
|
|
||||||
|
cell_search::args_t get_cell_search() const
|
||||||
|
{
|
||||||
|
cell_search::args_t ret = {};
|
||||||
|
ret.max_srate_hz = srate_hz;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
slot_sync::args_t get_slot_sync() const
|
||||||
|
{
|
||||||
|
slot_sync::args_t ret = {};
|
||||||
|
ret.max_srate_hz = srate_hz;
|
||||||
|
ret.nof_rx_channels = nof_rx_channels;
|
||||||
|
ret.ssb_min_scs = ssb_min_scs;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
STATE_IDLE = 0, ///< No process is in progress
|
||||||
|
STATE_CELL_SEARCH,
|
||||||
|
STATE_CELL_SELECT
|
||||||
|
} state_t;
|
||||||
|
|
||||||
|
sync_sa(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_, worker_pool& workers_);
|
||||||
|
~sync_sa();
|
||||||
|
|
||||||
|
bool init(const args_t& args_);
|
||||||
|
|
||||||
|
// The following methods control the SYNC state machine
|
||||||
|
bool start_cell_search(const cell_search::cfg_t& cfg);
|
||||||
|
bool start_cell_select();
|
||||||
|
bool go_idle();
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
void worker_end(const worker_context_t& w_ctx, const bool& tx_enable, srsran::rf_buffer_t& buffer) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
stack_interface_phy_sa_nr& stack; ///< Stand-Alone RRC interface
|
||||||
|
srsran::radio_interface_phy& radio; ///< Radio object
|
||||||
|
srslog::basic_logger& logger; ///< General PHY logger
|
||||||
|
worker_pool& workers;
|
||||||
|
|
||||||
|
state_t state = STATE_IDLE;
|
||||||
|
state_t next_state = STATE_IDLE;
|
||||||
|
std::mutex state_mutex;
|
||||||
|
std::condition_variable state_cvar;
|
||||||
|
std::atomic<bool> running = {false};
|
||||||
|
uint32_t sf_sz = 0; ///< Subframe size (1-ms)
|
||||||
|
srsran::tti_semaphore<void*> tti_semaphore;
|
||||||
|
|
||||||
|
cell_search searcher;
|
||||||
|
slot_sync slot_synchronizer;
|
||||||
|
|
||||||
|
// FSM States
|
||||||
|
void run_state_idle();
|
||||||
|
void run_state_cell_search();
|
||||||
|
void run_state_cell_select();
|
||||||
|
|
||||||
|
// FSM transitions
|
||||||
|
void enter_state_idle();
|
||||||
|
|
||||||
|
void run_thread() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace nr
|
||||||
|
} // namespace srsue
|
||||||
|
|
||||||
|
#endif // SRSUE_SYNC_NR_SA_H
|
@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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 SRSUE_PHY_NR_SA_H
|
||||||
|
#define SRSUE_PHY_NR_SA_H
|
||||||
|
|
||||||
|
#include "srsran/interfaces/ue_nr_interfaces.h"
|
||||||
|
#include "srsue/hdr/phy/nr/sync_sa.h"
|
||||||
|
|
||||||
|
namespace srsue {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief NR Standalone PHY
|
||||||
|
*/
|
||||||
|
class phy_nr_sa : public phy_interface_stack_sa_nr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct args_t {
|
||||||
|
std::string log_level = "info"; ///< General PHY logging level
|
||||||
|
double srate_hz = 61.44e6; ///< Sampling rate in Hz
|
||||||
|
|
||||||
|
// Frequency allocation parameters
|
||||||
|
uint32_t pointA_arfcn = 0; ///< Resource grid PointA ARFCN
|
||||||
|
float pointA_Hz = 0; ///< Resource grid PointA frequency in Hz. Overrides pointA_arfcn if valid
|
||||||
|
uint32_t ssb_arfcn = 0; ///< SS/PBCH block center point ARFCN
|
||||||
|
float ssb_Hz = 0; ///< SS/PBCH block center point ARFCN. Overrides ssb_arfcn if valid
|
||||||
|
};
|
||||||
|
|
||||||
|
phy_nr_sa(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_);
|
||||||
|
|
||||||
|
bool init(const args_t& args);
|
||||||
|
|
||||||
|
int set_ul_grant(std::array<uint8_t, 27> packed_ul_grant, uint16_t rnti, srsran_rnti_type_t rnti_type) override
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int tx_request(const tx_request_t& request) override { return 0; }
|
||||||
|
void send_prach(const uint32_t prach_occasion,
|
||||||
|
const int preamble_index,
|
||||||
|
const float preamble_received_target_power,
|
||||||
|
const float ta_base_sec) override
|
||||||
|
{}
|
||||||
|
bool has_valid_sr_resource(uint32_t sr_id) override { return false; }
|
||||||
|
void clear_pending_grants() override {}
|
||||||
|
bool set_config(const srsran::phy_cfg_nr_t& cfg) override { return false; }
|
||||||
|
|
||||||
|
phy_nr_sa_state_t get_state() const override { return PHY_NR_SA_STATE_CELL_SELECT; }
|
||||||
|
void reset() override {}
|
||||||
|
bool start_cell_search(const cell_search_args_t& req) override { return false; }
|
||||||
|
bool start_cell_select(const cell_search_args_t& req) override { return false; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
nr::worker_pool workers;
|
||||||
|
nr::sync_sa sync;
|
||||||
|
srslog::basic_logger& logger;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace srsue
|
||||||
|
#endif // SRSUE_PHY_NR_SA_H
|
@ -0,0 +1,126 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "srsue/hdr/phy/nr/cell_search.h"
|
||||||
|
#include "srsran/common/band_helper.h"
|
||||||
|
#include "srsran/common/buffer_pool.h"
|
||||||
|
#include "srsran/radio/rf_buffer.h"
|
||||||
|
#include "srsran/radio/rf_timestamp.h"
|
||||||
|
|
||||||
|
namespace srsue {
|
||||||
|
namespace nr {
|
||||||
|
cell_search::cell_search(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_) :
|
||||||
|
logger(srslog::fetch_basic_logger("PHY")),
|
||||||
|
stack(stack_),
|
||||||
|
radio(radio_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
cell_search::~cell_search()
|
||||||
|
{
|
||||||
|
srsran_ssb_free(&ssb);
|
||||||
|
if (buffer != nullptr) {
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell_search::init(const args_t& args)
|
||||||
|
{
|
||||||
|
// Compute subframe size
|
||||||
|
sf_sz = (uint32_t)(args.max_srate_hz / 1000.0f);
|
||||||
|
|
||||||
|
// Allocate receive buffer
|
||||||
|
buffer = srsran_vec_cf_malloc(2 * sf_sz);
|
||||||
|
if (buffer == nullptr) {
|
||||||
|
logger.error("Error allocating buffer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare SSB initialization arguments
|
||||||
|
srsran_ssb_args_t ssb_args = {};
|
||||||
|
ssb_args.max_srate_hz = args.max_srate_hz;
|
||||||
|
ssb_args.min_scs = args.ssb_min_scs;
|
||||||
|
ssb_args.enable_search = true;
|
||||||
|
ssb_args.enable_decode = true;
|
||||||
|
|
||||||
|
// Initialise SSB
|
||||||
|
if (srsran_ssb_init(&ssb, &ssb_args) < SRSRAN_SUCCESS) {
|
||||||
|
logger.error("Cell search: Error initiating SSB");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell_search::start(const cfg_t& cfg)
|
||||||
|
{
|
||||||
|
// Prepare SSB configuration
|
||||||
|
srsran_ssb_cfg_t ssb_cfg = {};
|
||||||
|
ssb_cfg.srate_hz = cfg.srate_hz;
|
||||||
|
ssb_cfg.center_freq_hz = cfg.center_freq_hz;
|
||||||
|
ssb_cfg.ssb_freq_hz = cfg.ssb_freq_hz;
|
||||||
|
ssb_cfg.scs = cfg.ssb_scs;
|
||||||
|
ssb_cfg.pattern = cfg.ssb_pattern;
|
||||||
|
ssb_cfg.duplex_mode = cfg.duplex_mode;
|
||||||
|
|
||||||
|
// Configure SSB
|
||||||
|
if (srsran_ssb_set_cfg(&ssb, &ssb_cfg) < SRSRAN_SUCCESS) {
|
||||||
|
logger.error("Cell search: Error setting SSB configuration");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set RX frequency
|
||||||
|
radio.set_rx_freq(0, cfg.center_freq_hz);
|
||||||
|
|
||||||
|
// Zero receive buffer
|
||||||
|
srsran_vec_zero(buffer, sf_sz);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cell_search::run()
|
||||||
|
{
|
||||||
|
// Setup RF buffer for 1ms worth of samples
|
||||||
|
srsran::rf_buffer_t rf_buffer = {};
|
||||||
|
rf_buffer.set_nof_samples(sf_sz);
|
||||||
|
rf_buffer.set(0, buffer + ssb.ssb_sz);
|
||||||
|
|
||||||
|
// Receive
|
||||||
|
srsran::rf_timestamp_t rf_timestamp = {};
|
||||||
|
if (not radio.rx_now(rf_buffer, rf_timestamp)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for SSB
|
||||||
|
srsran_ssb_search_res_t res = {};
|
||||||
|
if (srsran_ssb_search(&ssb, buffer, sf_sz + ssb.ssb_sz, &res) < SRSRAN_SUCCESS) {
|
||||||
|
logger.error("Error occurred searching SSB");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consider the SSB is found and decoded if the PBCH CRC matched
|
||||||
|
if (res.pbch_msg.crc) {
|
||||||
|
rrc_interface_phy_sa_nr::cell_search_result_t cs_res = {};
|
||||||
|
cs_res.pci = res.N_id;
|
||||||
|
cs_res.barred = false;
|
||||||
|
cs_res.intra_freq_meas = false;
|
||||||
|
cs_res.measurements = res.measurements;
|
||||||
|
stack.cell_search_found_cell(cs_res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance stack TTI
|
||||||
|
stack.run_tti(0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace nr
|
||||||
|
} // namespace srsue
|
@ -0,0 +1,132 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "srsue/hdr/phy/nr/slot_sync.h"
|
||||||
|
|
||||||
|
namespace srsue {
|
||||||
|
namespace nr {
|
||||||
|
|
||||||
|
slot_sync::slot_sync(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_) :
|
||||||
|
logger(srslog::fetch_basic_logger("PHY")),
|
||||||
|
stack(stack_),
|
||||||
|
radio(radio_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
slot_sync::~slot_sync()
|
||||||
|
{
|
||||||
|
srsran_ue_sync_nr_free(&ue_sync_nr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sync_sa_recv_callback(void* ptr, cf_t** buffer, uint32_t nsamples, srsran_timestamp_t* ts)
|
||||||
|
{
|
||||||
|
if (ptr == nullptr) {
|
||||||
|
return SRSRAN_ERROR_INVALID_INPUTS;
|
||||||
|
}
|
||||||
|
slot_sync* sync = (slot_sync*)ptr;
|
||||||
|
srsran::rf_buffer_t rf_buffer(buffer, nsamples);
|
||||||
|
|
||||||
|
return sync->recv_callback(rf_buffer, ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool slot_sync::init(const args_t& args)
|
||||||
|
{
|
||||||
|
srsran_ue_sync_nr_args_t ue_sync_nr_args = {};
|
||||||
|
ue_sync_nr_args.max_srate_hz = args.max_srate_hz;
|
||||||
|
ue_sync_nr_args.min_scs = args.ssb_min_scs;
|
||||||
|
ue_sync_nr_args.nof_rx_channels = args.nof_rx_channels;
|
||||||
|
ue_sync_nr_args.disable_cfo = args.disable_cfo;
|
||||||
|
ue_sync_nr_args.pbch_dmrs_thr = args.pbch_dmrs_thr;
|
||||||
|
ue_sync_nr_args.cfo_alpha = args.cfo_alpha;
|
||||||
|
|
||||||
|
if (srsran_ue_sync_nr_init(&ue_sync_nr, &ue_sync_nr_args) < SRSRAN_SUCCESS) {
|
||||||
|
logger.error("Error initiating UE SYNC NR object");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int slot_sync::recv_callback(srsran::rf_buffer_t& data, srsran_timestamp_t* rx_time)
|
||||||
|
{
|
||||||
|
// This function is designed for being called from the UE sync object which will pass a null rx_time in case
|
||||||
|
// receive dummy samples. So, rf_timestamp points at dummy timestamp in case rx_time is not provided
|
||||||
|
srsran::rf_timestamp_t dummy_ts = {};
|
||||||
|
srsran::rf_timestamp_t& rf_timestamp = (rx_time == nullptr) ? dummy_ts : last_rx_time;
|
||||||
|
|
||||||
|
// Receive
|
||||||
|
if (not radio.rx_now(data, rf_timestamp)) {
|
||||||
|
return SRSRAN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
srsran_timestamp_t dummy_flat_ts = {};
|
||||||
|
|
||||||
|
// Load flat timestamp
|
||||||
|
if (rx_time == nullptr) {
|
||||||
|
rx_time = &dummy_flat_ts;
|
||||||
|
}
|
||||||
|
*rx_time = rf_timestamp.get(0);
|
||||||
|
|
||||||
|
// Save RF timestamp for the stack
|
||||||
|
stack_tti_ts_new = rf_timestamp.get(0);
|
||||||
|
|
||||||
|
// Run stack if the sync state is not in camping
|
||||||
|
if (state == SEARCHING) {
|
||||||
|
logger.debug("run_stack_tti: from recv");
|
||||||
|
run_stack_tti();
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("SYNC: received %d samples from radio", data.get_nof_samples());
|
||||||
|
|
||||||
|
return data.get_nof_samples();
|
||||||
|
}
|
||||||
|
|
||||||
|
void slot_sync::run_stack_tti()
|
||||||
|
{ // check timestamp reset
|
||||||
|
if (forced_rx_time_init || srsran_timestamp_iszero(&stack_tti_ts) ||
|
||||||
|
srsran_timestamp_compare(&stack_tti_ts_new, &stack_tti_ts) < 0) {
|
||||||
|
if (srsran_timestamp_compare(&stack_tti_ts_new, &stack_tti_ts) < 0) {
|
||||||
|
logger.warning("SYNC: radio time seems to be going backwards (rx_time=%f, tti_ts=%f)",
|
||||||
|
srsran_timestamp_real(&stack_tti_ts_new),
|
||||||
|
srsran_timestamp_real(&stack_tti_ts));
|
||||||
|
// time-stamp will be set to rx time below and run_tti() will be called with MIN_TTI_JUMP
|
||||||
|
}
|
||||||
|
|
||||||
|
// init tti_ts with last rx time
|
||||||
|
logger.debug("SYNC: Setting initial TTI time to %f", srsran_timestamp_real(&stack_tti_ts_new));
|
||||||
|
srsran_timestamp_copy(&stack_tti_ts, &stack_tti_ts_new);
|
||||||
|
forced_rx_time_init = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance stack in time
|
||||||
|
if (srsran_timestamp_compare(&stack_tti_ts_new, &stack_tti_ts) >= 0) {
|
||||||
|
srsran_timestamp_t temp = {};
|
||||||
|
srsran_timestamp_copy(&temp, &stack_tti_ts_new);
|
||||||
|
srsran_timestamp_sub(&temp, stack_tti_ts.full_secs, stack_tti_ts.frac_secs);
|
||||||
|
int32_t tti_jump = static_cast<int32_t>(srsran_timestamp_uint64(&temp, 1e3));
|
||||||
|
tti_jump = SRSRAN_MAX(tti_jump, MIN_TTI_JUMP);
|
||||||
|
if (tti_jump > MAX_TTI_JUMP) {
|
||||||
|
logger.warning("SYNC: TTI jump of %d limited to %d", tti_jump, int(MAX_TTI_JUMP));
|
||||||
|
tti_jump = SRSRAN_MIN(tti_jump, MAX_TTI_JUMP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run stack
|
||||||
|
logger.debug("run_stack_tti: calling stack tti=%d, tti_jump=%d", tti, tti_jump);
|
||||||
|
stack.run_tti(tti);
|
||||||
|
logger.debug("run_stack_tti: stack called");
|
||||||
|
}
|
||||||
|
|
||||||
|
// update timestamp
|
||||||
|
srsran_timestamp_copy(&stack_tti_ts, &stack_tti_ts_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace nr
|
||||||
|
} // namespace srsue
|
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "srsue/hdr/phy/phy_nr_sa.h"
|
||||||
|
|
||||||
|
namespace srsue {
|
||||||
|
|
||||||
|
phy_nr_sa::phy_nr_sa(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_) :
|
||||||
|
logger(srslog::fetch_basic_logger("PHY-NR")),
|
||||||
|
sync(stack_, radio_, workers),
|
||||||
|
workers(4)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool phy_nr_sa::init(const args_t& args)
|
||||||
|
{
|
||||||
|
nr::sync_sa::args_t sync_args = {};
|
||||||
|
sync_args.srate_hz = args.srate_hz;
|
||||||
|
if (not sync.init(sync_args)) {
|
||||||
|
logger.error("Error initialising SYNC");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace srsue
|
@ -0,0 +1,149 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "srsue/hdr/phy/nr/sync_sa.h"
|
||||||
|
#include "srsran/radio/rf_buffer.h"
|
||||||
|
|
||||||
|
namespace srsue {
|
||||||
|
namespace nr {
|
||||||
|
sync_sa::sync_sa(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_, worker_pool& workers_) :
|
||||||
|
logger(srslog::fetch_basic_logger("PHY-NR")),
|
||||||
|
stack(stack_),
|
||||||
|
radio(radio_),
|
||||||
|
workers(workers_),
|
||||||
|
srsran::thread("SYNC"),
|
||||||
|
searcher(stack_, radio_),
|
||||||
|
slot_synchronizer(stack_, radio_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
sync_sa::~sync_sa() {}
|
||||||
|
|
||||||
|
bool sync_sa::init(const args_t& args)
|
||||||
|
{
|
||||||
|
sf_sz = (uint32_t)(args.srate_hz / 1000.0f);
|
||||||
|
|
||||||
|
// Initialise cell search internal object
|
||||||
|
if (not searcher.init(args.get_cell_search())) {
|
||||||
|
logger.error("Error initialising cell searcher");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise slot synchronizer object
|
||||||
|
if (not slot_synchronizer.init(args.get_slot_sync())) {
|
||||||
|
logger.error("Error initialising slot synchronizer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thread control
|
||||||
|
running = true;
|
||||||
|
start(args.thread_priority);
|
||||||
|
|
||||||
|
// If reached here it was successful
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sync_sa::start_cell_search(const cell_search::cfg_t& cfg)
|
||||||
|
{
|
||||||
|
// Make sure current state is IDLE
|
||||||
|
std::unique_lock<std::mutex> lock(state_mutex);
|
||||||
|
if (state != STATE_IDLE or next_state != STATE_IDLE) {
|
||||||
|
logger.error("Sync: trying to start cell search but state is not IDLE");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure searcher without locking state
|
||||||
|
lock.unlock();
|
||||||
|
if (not searcher.start(cfg)) {
|
||||||
|
logger.error("Sync: failed to start cell search");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
// Transition to search
|
||||||
|
next_state = STATE_CELL_SEARCH;
|
||||||
|
|
||||||
|
// Wait for state transition
|
||||||
|
while (state != STATE_CELL_SEARCH) {
|
||||||
|
state_cvar.wait(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sync_sa::start_cell_select()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sync_sa::go_idle()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(state_mutex);
|
||||||
|
|
||||||
|
// Force transition to IDLE
|
||||||
|
while (state != STATE_IDLE) {
|
||||||
|
next_state = STATE_IDLE;
|
||||||
|
state_cvar.wait(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait worker pool to finish any processing
|
||||||
|
tti_semaphore.wait_all();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sync_sa::stop()
|
||||||
|
{
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sync_sa::run_state_idle()
|
||||||
|
{
|
||||||
|
srsran::rf_buffer_t rf_buffer = {};
|
||||||
|
rf_buffer.set_nof_samples(sf_sz);
|
||||||
|
|
||||||
|
srsran::rf_timestamp_t ts = {};
|
||||||
|
|
||||||
|
radio.rx_now(rf_buffer, ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sync_sa::run_state_cell_search() {}
|
||||||
|
|
||||||
|
void sync_sa::run_thread()
|
||||||
|
{
|
||||||
|
while (running) {
|
||||||
|
state_mutex.lock();
|
||||||
|
// Detect state transition
|
||||||
|
if (next_state != state) {
|
||||||
|
state = next_state;
|
||||||
|
state_cvar.notify_all();
|
||||||
|
}
|
||||||
|
state_t current_state = state;
|
||||||
|
state_mutex.unlock();
|
||||||
|
|
||||||
|
switch (current_state) {
|
||||||
|
case STATE_IDLE:
|
||||||
|
run_state_idle();
|
||||||
|
break;
|
||||||
|
case STATE_CELL_SEARCH:
|
||||||
|
run_state_cell_search();
|
||||||
|
break;
|
||||||
|
case STATE_CELL_SELECT:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void sync_sa::worker_end(const srsran::phy_common_interface::worker_context_t& w_ctx,
|
||||||
|
const bool& tx_enable,
|
||||||
|
srsran::rf_buffer_t& buffer)
|
||||||
|
{}
|
||||||
|
|
||||||
|
} // namespace nr
|
||||||
|
} // namespace srsue
|
@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "srsue/hdr/phy/phy_nr_sa.h"
|
||||||
|
|
||||||
|
struct test_args_t {};
|
||||||
|
|
||||||
|
class gnb_emulator : public srsran::radio_interface_phy
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// srsran_ssb_t ssb = {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct args_t {
|
||||||
|
double srate_hz;
|
||||||
|
};
|
||||||
|
gnb_emulator() {}
|
||||||
|
void tx_end() override {}
|
||||||
|
bool tx(srsran::rf_buffer_interface& buffer, const srsran::rf_timestamp_interface& tx_time) override { return false; }
|
||||||
|
bool rx_now(srsran::rf_buffer_interface& buffer, srsran::rf_timestamp_interface& rxd_time) override { return false; }
|
||||||
|
void set_tx_freq(const uint32_t& carrier_idx, const double& freq) override {}
|
||||||
|
void set_rx_freq(const uint32_t& carrier_idx, const double& freq) override {}
|
||||||
|
void release_freq(const uint32_t& carrier_idx) override {}
|
||||||
|
void set_tx_gain(const float& gain) override {}
|
||||||
|
void set_rx_gain_th(const float& gain) override {}
|
||||||
|
void set_rx_gain(const float& gain) override {}
|
||||||
|
void set_tx_srate(const double& srate) override {}
|
||||||
|
void set_rx_srate(const double& srate) override {}
|
||||||
|
void set_channel_rx_offset(uint32_t ch, int32_t offset_samples) override {}
|
||||||
|
double get_freq_offset() override { return 0; }
|
||||||
|
float get_rx_gain() override { return 0; }
|
||||||
|
bool is_continuous_tx() override { return false; }
|
||||||
|
bool get_is_start_of_burst() override { return false; }
|
||||||
|
bool is_init() override { return false; }
|
||||||
|
void reset() override {}
|
||||||
|
srsran_rf_info_t* get_info() override { return nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue