/** * * \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/scell/intra_measure_nr.h" #define Log(level, fmt, ...) \ do { \ logger.level("INTRA-%s: " fmt, to_string(get_rat()).c_str(), ##__VA_ARGS__); \ } while (false) namespace srsue { namespace scell { intra_measure_nr::intra_measure_nr(srslog::basic_logger& logger_, meas_itf& new_meas_itf_) : logger(logger_), intra_measure_base(logger_, new_meas_itf_) {} intra_measure_nr::~intra_measure_nr() { srsran_ssb_free(&ssb); } bool intra_measure_nr::init(uint32_t cc_idx_, const args_t& args) { cc_idx = cc_idx_; thr_snr_db = args.thr_snr_db; // Initialise generic side intra_measure_base::args_t base_args = {}; base_args.srate_hz = args.max_srate_hz; base_args.len_ms = args.max_len_ms; base_args.period_ms = 20; // Hard-coded, it does not make a difference at this stage base_args.rx_gain_offset_db = args.rx_gain_offset_dB; init_generic(cc_idx, base_args); // Initialise SSB srsran_ssb_args_t ssb_args = {}; ssb_args.max_srate_hz = args.max_srate_hz; ssb_args.min_scs = args.min_scs; ssb_args.enable_search = true; if (srsran_ssb_init(&ssb, &ssb_args) < SRSRAN_SUCCESS) { Log(error, "Error initiating SSB"); return false; } return true; } bool intra_measure_nr::set_config(uint32_t arfcn, const config_t& cfg) { // Update ARFCN current_arfcn = arfcn; serving_cell_pci = cfg.serving_cell_pci; // Configure generic side intra_measure_base::args_t base_cfg = {}; base_cfg.srate_hz = cfg.srate_hz; base_cfg.len_ms = cfg.len_ms; base_cfg.period_ms = cfg.periodicity_ms; base_cfg.rx_gain_offset_db = cfg.rx_gain_offset_db; init_generic(cc_idx, base_cfg); // Configure SSB 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.scs; if (srsran_ssb_set_cfg(&ssb, &ssb_cfg) < SRSRAN_SUCCESS) { Log(error, "Error configuring SSB"); return false; } return true; } void intra_measure_nr::measure_rat(const measure_context_t& context, std::vector& buffer) { // Search and measure the best cell srsran_csi_trs_measurements_t meas = {}; uint32_t N_id = 0; if (srsran_ssb_csi_search(&ssb, buffer.data(), context.sf_len * context.meas_len_ms, &N_id, &meas) < SRSRAN_SUCCESS) { Log(error, "Error searching for SSB"); } // Early return if the found PCI matches with the serving cell ID if (serving_cell_pci == (int)N_id) { return; } // Check threshold if (meas.snr_dB >= thr_snr_db) { // Log finding if (logger.info.enabled()) { std::array str_info = {}; srsran_csi_rs_measure_info(&meas, str_info.data(), (uint32_t)str_info.size()); Log(info, "Found neighbour cell: ARFCN=%d PCI=%03d %s", get_earfcn(), N_id, str_info.data()); } // Prepare found measurements std::vector meas_list(1); meas_list[0].rat = get_rat(); meas_list[0].rsrp = meas.rsrp_dB + context.rx_gain_offset_db; meas_list[0].cfo_hz = meas.cfo_hz; meas_list[0].earfcn = get_earfcn(); meas_list[0].pci = N_id; // Push measurements to higher layers context.new_cell_itf.new_cell_meas(cc_idx, meas_list); } } } // namespace scell } // namespace srsue