Merge branch 'next' into agpl_next

# Conflicts:
#	lib/include/srsran/common/signal_handler.h
master
Codebot 3 years ago committed by Your Name
commit 9d7836817c

@ -291,10 +291,13 @@ public:
bool push_blocking(const T& t) { return push_(t, true); } bool push_blocking(const T& t) { return push_(t, true); }
srsran::error_type<T> push_blocking(T&& t) { return push_(std::move(t), true); } srsran::error_type<T> push_blocking(T&& t) { return push_(std::move(t), true); }
bool try_pop(T& obj) { return pop_(obj, false); } bool try_pop(T& obj) { return pop_(obj, false); }
T pop_blocking() T pop_blocking(bool* success = nullptr)
{ {
T obj{}; T obj{};
pop_(obj, true); bool ret = pop_(obj, true);
if (success != nullptr) {
*success = ret;
}
return obj; return obj;
} }
bool pop_wait_until(T& obj, const std::chrono::system_clock::time_point& until) { return pop_(obj, true, &until); } bool pop_wait_until(T& obj, const std::chrono::system_clock::time_point& until) { return pop_(obj, true, &until); }
@ -599,12 +602,6 @@ public:
base_t(push_callback, pop_callback, size) base_t(push_callback, pop_callback, size)
{} {}
void set_size(size_t size) { base_t::circ_buffer.set_size(size); } void set_size(size_t size) { base_t::circ_buffer.set_size(size); }
template <typename F>
bool apply_first(const F& func)
{
return base_t::apply_first(func);
}
}; };
} // namespace srsran } // namespace srsran

@ -608,7 +608,7 @@ public:
IntType value; IntType value;
integer() = default; integer() = default;
integer(IntType value_) : value(value_) {} integer(IntType value_) : value(value_) {}
operator IntType() { return value; } operator IntType() const { return value; }
SRSASN_CODE pack(bit_ref& bref) const { return pack_integer(bref, value, lb, ub, has_ext, is_aligned); } SRSASN_CODE pack(bit_ref& bref) const { return pack_integer(bref, value, lb, ub, has_ext, is_aligned); }
SRSASN_CODE unpack(cbit_ref& bref) { return unpack_integer(value, bref, lb, ub, has_ext, is_aligned); } SRSASN_CODE unpack(cbit_ref& bref) { return unpack_integer(value, bref, lb, ub, has_ext, is_aligned); }
}; };
@ -1320,7 +1320,7 @@ private:
bit_ref brefstart; bit_ref brefstart;
// bit_ref bref0; // bit_ref bref0;
bit_ref* bref_tracker; bit_ref* bref_tracker;
uint8_t buffer[2048]; uint8_t buffer[4096];
bool align; bool align;
}; };
@ -1368,6 +1368,33 @@ private:
separator_t sep; separator_t sep;
}; };
template <typename T>
inline auto to_json(json_writer& j, const T& obj) -> decltype(obj.to_json(j))
{
obj.to_json(j);
}
template <typename T>
inline void to_json(json_writer& j, const asn1::enumerated<T>& obj)
{
j.write_str(obj.to_string());
}
template <typename T>
inline void to_json(json_writer& j, const asn1::dyn_array<T>& lst)
{
j.start_array();
for (const auto& o : lst) {
to_json(j, o);
}
j.end_array();
}
inline void to_json(json_writer& j, int64_t number)
{
j.write_int(number);
}
/******************* /*******************
Test pack/unpack Test pack/unpack
*******************/ *******************/

@ -2285,8 +2285,11 @@ struct setup_release_c {
j.start_obj(); j.start_obj();
switch (type_) { switch (type_) {
case types::release: case types::release:
j.write_null("release");
break; break;
case types::setup: case types::setup:
j.write_fieldname("setup");
asn1::to_json(j, setup());
break; break;
default: default:
log_invalid_choice_id(type_, "setup_release_c"); log_invalid_choice_id(type_, "setup_release_c");

@ -66,6 +66,8 @@ struct pdsch_serving_cell_cfg_s;
struct freq_info_dl_s; struct freq_info_dl_s;
struct serving_cell_cfg_common_s; struct serving_cell_cfg_common_s;
struct serving_cell_cfg_s; struct serving_cell_cfg_s;
struct pdcch_cfg_common_s;
struct pdcch_cfg_s;
} // namespace rrc_nr } // namespace rrc_nr
} // namespace asn1 } // namespace asn1
@ -123,7 +125,12 @@ bool make_phy_carrier_cfg(const asn1::rrc_nr::freq_info_dl_s& freq_info_dl, srsr
bool make_phy_ssb_cfg(const srsran_carrier_nr_t& carrier, bool make_phy_ssb_cfg(const srsran_carrier_nr_t& carrier,
const asn1::rrc_nr::serving_cell_cfg_common_s& serv_cell_cfg, const asn1::rrc_nr::serving_cell_cfg_common_s& serv_cell_cfg,
phy_cfg_nr_t::ssb_cfg_t* ssb); phy_cfg_nr_t::ssb_cfg_t* ssb);
bool make_pdsch_cfg_from_serv_cell(asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_sch_hl_cfg_nr_t* sch_hl); bool make_pdsch_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_sch_hl_cfg_nr_t* sch_hl);
bool make_csi_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_csi_hl_cfg_t* csi_hl);
bool make_duplex_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_common_s& serv_cell,
srsran_duplex_config_nr_t* duplex_cfg);
bool fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch);
bool fill_phy_pdcch_cfg(const asn1::rrc_nr::pdcch_cfg_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch);
/*************************** /***************************
* MAC Config * MAC Config

@ -60,7 +60,7 @@ public:
radio_bearer_t get_radio_bearer(uint32_t eps_bearer_id); radio_bearer_t get_radio_bearer(uint32_t eps_bearer_id);
radio_bearer_t get_lcid_bearer(uint32_t lcid); radio_bearer_t get_eps_bearer_id_for_lcid(uint32_t lcid);
private: private:
using eps_rb_map_t = std::map<uint32_t, radio_bearer_t>; using eps_rb_map_t = std::map<uint32_t, radio_bearer_t>;
@ -128,7 +128,7 @@ public:
radio_bearer_t get_lcid_bearer(uint32_t lcid) radio_bearer_t get_lcid_bearer(uint32_t lcid)
{ {
srsran::rwlock_read_guard rw_lock(rwlock); srsran::rwlock_read_guard rw_lock(rwlock);
return impl.get_lcid_bearer(lcid); return impl.get_eps_bearer_id_for_lcid(lcid);
} }
private: private:

@ -29,20 +29,20 @@
namespace srsran { namespace srsran {
typedef struct { struct phy_log_args_t {
std::string phy_level = "none"; std::string phy_level = "none";
std::string phy_lib_level = "none"; std::string phy_lib_level = "none";
std::string id_preamble = ""; std::string id_preamble = "";
int phy_hex_limit = -1; int phy_hex_limit = -1;
} phy_log_args_t; };
typedef struct { struct rf_args_band_t {
float min; float min;
float max; float max;
} rf_args_band_t; };
// RF/radio args // RF/radio args
typedef struct { struct rf_args_t {
std::string type; std::string type;
std::string log_level; std::string log_level;
double srate_hz; double srate_hz;
@ -65,8 +65,7 @@ typedef struct {
std::array<rf_args_band_t, SRSRAN_MAX_CARRIERS> ch_rx_bands; std::array<rf_args_band_t, SRSRAN_MAX_CARRIERS> ch_rx_bands;
std::array<rf_args_band_t, SRSRAN_MAX_CARRIERS> ch_tx_bands; std::array<rf_args_band_t, SRSRAN_MAX_CARRIERS> ch_tx_bands;
};
} rf_args_t;
struct vnf_args_t { struct vnf_args_t {
std::string type; std::string type;

@ -37,6 +37,12 @@ class mac_pcap_base : protected srsran::thread
{ {
public: public:
mac_pcap_base(); mac_pcap_base();
mac_pcap_base(const mac_pcap_base& other) = delete;
mac_pcap_base& operator=(const mac_pcap_base& other) = delete;
mac_pcap_base(mac_pcap_base&& other) = delete;
mac_pcap_base& operator=(mac_pcap_base&& other) = delete;
~mac_pcap_base(); ~mac_pcap_base();
void enable(bool enable); void enable(bool enable);
virtual uint32_t close() = 0; virtual uint32_t close() = 0;

@ -30,7 +30,12 @@ namespace srsran {
class s1ap_pcap class s1ap_pcap
{ {
public: public:
s1ap_pcap() = default; s1ap_pcap();
s1ap_pcap(const s1ap_pcap& other) = delete;
s1ap_pcap& operator=(const s1ap_pcap& other) = delete;
s1ap_pcap(s1ap_pcap&& other) = delete;
s1ap_pcap& operator=(s1ap_pcap&& other) = delete;
void enable(); void enable();
void open(const char* filename_); void open(const char* filename_);
void close(); void close();

@ -1,83 +0,0 @@
/**
* Copyright 2013-2021 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsRAN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/**
* @file signal_handler.h
* @brief Common signal handling methods for all srsRAN applications.
*/
#ifndef SRSRAN_SIGNAL_HANDLER_H
#define SRSRAN_SIGNAL_HANDLER_H
#include "srsran/srslog/sink.h"
#include "srsran/srslog/srslog.h"
#include <signal.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#define SRSRAN_TERM_TIMEOUT_S (5)
// static vars required by signal handling
static srslog::sink* log_sink = nullptr;
static std::atomic<bool> running = {true};
void srsran_dft_exit();
static void srsran_signal_handler(int signal)
{
switch (signal) {
case SIGALRM:
fprintf(stderr, "Couldn't stop after %ds. Forcing exit.\n", SRSRAN_TERM_TIMEOUT_S);
srslog::flush();
//:TODO: refactor the sighandler, should not depend on log utilities
if (log_sink) {
log_sink->flush();
}
srsran_dft_exit();
raise(SIGKILL);
default:
// all other registered signals try to stop the app gracefully
if (running) {
running = false;
fprintf(stdout, "Stopping ..\n");
alarm(SRSRAN_TERM_TIMEOUT_S);
} else {
// already waiting for alarm to go off ..
}
break;
}
}
void srsran_register_signal_handler()
{
signal(SIGINT, srsran_signal_handler);
signal(SIGTERM, srsran_signal_handler);
signal(SIGHUP, srsran_signal_handler);
signal(SIGALRM, srsran_signal_handler);
}
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // SRSRAN_SIGNAL_HANDLER_H

@ -153,6 +153,40 @@ private:
bool running = false; bool running = false;
}; };
/// Class used to create a single worker with an input task queue with a single reader
class task_worker : public thread
{
using task_t = srsran::move_callback<void(), default_move_callback_buffer_size, true>;
public:
task_worker(std::string thread_name_,
uint32_t queue_size,
bool start_deferred = false,
int32_t prio_ = -1,
uint32_t mask_ = 255);
task_worker(const task_worker&) = delete;
task_worker(task_worker&&) = delete;
task_worker& operator=(const task_worker&) = delete;
task_worker& operator=(task_worker&&) = delete;
~task_worker();
void stop();
void start(int32_t prio_ = -1, uint32_t mask_ = 255);
void push_task(task_t&& task);
uint32_t nof_pending_tasks() const;
private:
void run_thread() override;
// args
int32_t prio = -1;
uint32_t mask = 255;
srslog::basic_logger& logger;
srsran::dyn_blocking_queue<task_t> pending_tasks;
};
srsran::task_thread_pool& get_background_workers(); srsran::task_thread_pool& get_background_workers();
} // namespace srsran } // namespace srsran

@ -50,8 +50,16 @@ const char* __tsan_default_suppressions()
// External uninstrumented libraries // External uninstrumented libraries
"called_from_lib:libzmq.so\n" "called_from_lib:libzmq.so\n"
"called_from_lib:libpgm-5.2.so\n" "called_from_lib:libpgm-5.2.so\n"
// Lock order inversion issue in this function, ignore it as it uses rw locks in read mode "called_from_lib:libusb*\n"
"deadlock:srsenb::mac::rlc_buffer_state\n"; "called_from_lib:libuhd*\n"
// Races detected inside uninstrumented libraries. This may hide legit races if any of the libraries appear in the
// backtrace
"race:libusb*\n"
"race:libuhd*\n"
// Lock order inversion issues in these functions, ignore it as it uses rw locks in read mode
"deadlock:srsenb::mac::rlc_buffer_state\n"
"deadlock:srsenb::mac::snr_info\n"
"deadlock:srsenb::mac::ack_info\n";
} }
#ifdef __cplusplus #ifdef __cplusplus

@ -31,7 +31,6 @@ struct mac_args_t {
uint32_t nof_prb; ///< Needed to dimension MAC softbuffers for all cells uint32_t nof_prb; ///< Needed to dimension MAC softbuffers for all cells
sched_interface::sched_args_t sched; sched_interface::sched_args_t sched;
int lcid_padding; int lcid_padding;
int nr_tb_size = -1;
uint32_t nof_prealloc_ues; ///< Number of UE resources to pre-allocate at eNB startup uint32_t nof_prealloc_ues; ///< Number of UE resources to pre-allocate at eNB startup
uint32_t max_nof_kos; uint32_t max_nof_kos;
int rlf_min_ul_snr_estim; int rlf_min_ul_snr_estim;

@ -45,10 +45,13 @@ public:
}; };
/// Request addition of NR carrier for UE /// Request addition of NR carrier for UE
virtual int sgnb_addition_request(uint16_t eutra_rnti, const sgnb_addition_req_params_t& params) = 0; virtual void sgnb_addition_request(uint16_t eutra_rnti, const sgnb_addition_req_params_t& params) = 0;
/// Provide information whether the requested configuration was applied successfully by the UE /// Provide information whether the requested configuration was applied successfully by the UE
virtual int sgnb_reconfiguration_complete(uint16_t eutra_rnti, asn1::dyn_octstring reconfig_response) = 0; virtual void sgnb_reconfiguration_complete(uint16_t eutra_rnti, const asn1::dyn_octstring& reconfig_response) = 0;
/// Trigger release for specific UE
virtual void sgnb_release_request(uint16_t nr_rnti) = 0;
}; };
/// X2AP inspired interface for response from NR RRC to EUTRA RRC /// X2AP inspired interface for response from NR RRC to EUTRA RRC
@ -91,6 +94,13 @@ public:
*/ */
virtual void sgnb_addition_complete(uint16_t eutra_rnti, uint16_t nr_rnti) = 0; virtual void sgnb_addition_complete(uint16_t eutra_rnti, uint16_t nr_rnti) = 0;
/**
* @brief Signal release of all UE resources on the NR cell
*
* @param eutra_rnti The RNTI that the EUTRA RRC used to request the SgNB addition
*/
virtual void sgnb_release_ack(uint16_t eutra_rnti) = 0;
/** /**
* @brief Signal user activity (i.e. DL/UL traffic) for given RNTI * @brief Signal user activity (i.e. DL/UL traffic) for given RNTI
* *
@ -104,7 +114,10 @@ class x2_interface : public rrc_nr_interface_rrc,
public rrc_eutra_interface_rrc_nr, public rrc_eutra_interface_rrc_nr,
public pdcp_interface_gtpu, // allow GTPU to access PDCP in DL direction public pdcp_interface_gtpu, // allow GTPU to access PDCP in DL direction
public gtpu_interface_pdcp // allow PDCP to access GTPU in UL direction public gtpu_interface_pdcp // allow PDCP to access GTPU in UL direction
{}; {
public:
virtual ~x2_interface() = default;
};
} // namespace srsenb } // namespace srsenb

@ -36,6 +36,8 @@
namespace srsenb { namespace srsenb {
struct sched_nr_ue_cfg_t;
/***************************** /*****************************
* RLC INTERFACES * RLC INTERFACES
****************************/ ****************************/
@ -143,7 +145,7 @@ public:
virtual int read_pdu_bcch_dlsch(uint32_t sib_index, srsran::unique_byte_buffer_t& buffer) = 0; virtual int read_pdu_bcch_dlsch(uint32_t sib_index, srsran::unique_byte_buffer_t& buffer) = 0;
/// User management /// User management
virtual int add_user(uint16_t rnti) = 0; virtual int add_user(uint16_t rnti, const sched_nr_ue_cfg_t& uecfg) = 0;
virtual int update_user(uint16_t new_rnti, uint16_t old_rnti) = 0; virtual int update_user(uint16_t new_rnti, uint16_t old_rnti) = 0;
virtual void set_activity_user(uint16_t rnti) = 0; virtual void set_activity_user(uint16_t rnti) = 0;
}; };
@ -277,7 +279,7 @@ public:
srsran::unique_byte_buffer_t pdu = nullptr; srsran::unique_byte_buffer_t pdu = nullptr;
// PUSCH signal measurements // PUSCH signal measurements
// ... srsran_csi_trs_measurements_t csi; ///< DMRS based signal Channel State Information (CSI)
}; };
struct rach_info_t { struct rach_info_t {

@ -33,7 +33,7 @@ public:
virtual int cell_cfg(const std::vector<srsenb::sched_nr_interface::cell_cfg_t>& nr_cells) = 0; virtual int cell_cfg(const std::vector<srsenb::sched_nr_interface::cell_cfg_t>& nr_cells) = 0;
/// Allocates a new user/RNTI at MAC. Returns RNTI on success or SRSRAN_INVALID_RNTI otherwise. /// Allocates a new user/RNTI at MAC. Returns RNTI on success or SRSRAN_INVALID_RNTI otherwise.
virtual uint16_t reserve_rnti(uint32_t enb_cc_idx) = 0; virtual uint16_t reserve_rnti(uint32_t enb_cc_idx, const sched_nr_interface::ue_cfg_t& uecfg) = 0;
virtual int ue_cfg(uint16_t rnti, const sched_nr_interface::ue_cfg_t& ue_cfg) = 0; virtual int ue_cfg(uint16_t rnti, const sched_nr_interface::ue_cfg_t& ue_cfg) = 0;

@ -38,6 +38,7 @@ public:
virtual int virtual int
establish_rrc_bearer(uint16_t rnti, uint16_t pdu_session_id, srsran::const_byte_span nas_pdu, uint32_t lcid) = 0; establish_rrc_bearer(uint16_t rnti, uint16_t pdu_session_id, srsran::const_byte_span nas_pdu, uint32_t lcid) = 0;
virtual int allocate_lcid(uint16_t rnti) = 0; virtual int allocate_lcid(uint16_t rnti) = 0;
virtual int release_bearers(uint16_t rnti) = 0;
virtual void write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) = 0; virtual void write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) = 0;
}; };

@ -155,6 +155,7 @@ public:
class mac_interface_rrc_nr class mac_interface_rrc_nr
{ {
public: public:
virtual void reset() = 0;
// Config calls that return SRSRAN_SUCCESS or SRSRAN_ERROR // Config calls that return SRSRAN_SUCCESS or SRSRAN_ERROR
virtual int setup_lcid(const srsran::logical_channel_config_t& config) = 0; virtual int setup_lcid(const srsran::logical_channel_config_t& config) = 0;
virtual int set_config(const srsran::bsr_cfg_nr_t& bsr_cfg) = 0; virtual int set_config(const srsran::bsr_cfg_nr_t& bsr_cfg) = 0;

@ -119,6 +119,7 @@ public:
uint32_t sk_counter_r15, uint32_t sk_counter_r15,
bool nr_radio_bearer_cfg1_r15_present, bool nr_radio_bearer_cfg1_r15_present,
asn1::dyn_octstring nr_radio_bearer_cfg1_r15) = 0; asn1::dyn_octstring nr_radio_bearer_cfg1_r15) = 0;
virtual void rrc_release() = 0;
virtual bool is_config_pending() = 0; virtual bool is_config_pending() = 0;
}; };

@ -68,7 +68,7 @@ public:
nr_lcid_sch_t get_type(); nr_lcid_sch_t get_type();
bool is_sdu(); bool is_sdu();
bool is_valid_lcid(); bool is_valid_lcid();
bool is_var_len_ce(); bool is_var_len_ce(uint32_t lcid);
bool is_ul_ccch(); bool is_ul_ccch();
int32_t read_subheader(const uint8_t* ptr); int32_t read_subheader(const uint8_t* ptr);
@ -89,7 +89,11 @@ public:
}; };
lcg_bsr_t get_sbsr(); lcg_bsr_t get_sbsr();
static const uint8_t max_num_lcg_lbsr = 8; static const uint8_t max_num_lcg_lbsr = 8;
std::array<lcg_bsr_t, max_num_lcg_lbsr> get_lbsr(); struct lbsr_t {
uint8_t bitmap; // the first octet of LBSR and Long Trunc BSR
std::vector<lcg_bsr_t> list; // one entry for each reported LCG
};
lbsr_t get_lbsr();
// TA // TA
struct ta_t { struct ta_t {
@ -116,6 +120,9 @@ public:
private: private:
srslog::basic_logger* logger; srslog::basic_logger* logger;
// internal helpers
bool has_length_field();
uint32_t lcid = 0; uint32_t lcid = 0;
int header_length = 0; int header_length = 0;
int sdu_length = 0; int sdu_length = 0;
@ -207,8 +214,9 @@ public:
void to_string(fmt::memory_buffer& buffer); void to_string(fmt::memory_buffer& buffer);
private:
uint32_t size_header_sdu(const uint32_t lcid_, const uint32_t nbytes); uint32_t size_header_sdu(const uint32_t lcid_, const uint32_t nbytes);
private:
/// Private helper that adds a subPDU to the MAC PDU /// Private helper that adds a subPDU to the MAC PDU
uint32_t add_sudpdu(mac_sch_subpdu_nr& subpdu); uint32_t add_sudpdu(mac_sch_subpdu_nr& subpdu);

@ -59,6 +59,8 @@ typedef struct {
cf_t* temp; /// Temporal data vector of size SRSRAN_NRE * carrier.nof_prb cf_t* temp; /// Temporal data vector of size SRSRAN_NRE * carrier.nof_prb
float* filter; ///< Smoothing filter float* filter; ///< Smoothing filter
srsran_csi_trs_measurements_t csi; ///< Last estimated channel state information
} srsran_dmrs_sch_t; } srsran_dmrs_sch_t;
/** /**

@ -37,7 +37,7 @@ namespace srsran {
class channel class channel
{ {
public: public:
typedef struct { struct args_t {
// General // General
bool enable = false; bool enable = false;
@ -67,7 +67,7 @@ public:
bool rlf_enable = false; bool rlf_enable = false;
uint32_t rlf_t_on_ms = 10000; uint32_t rlf_t_on_ms = 10000;
uint32_t rlf_t_off_ms = 2000; uint32_t rlf_t_off_ms = 2000;
} args_t; };
channel(const args_t& channel_args, uint32_t _nof_channels, srslog::basic_logger& logger); channel(const args_t& channel_args, uint32_t _nof_channels, srslog::basic_logger& logger);
~channel(); ~channel();

@ -654,7 +654,7 @@ SRSRAN_API bool srsran_duplex_nr_is_ul(const srsran_duplex_config_nr_t* cfg, uin
SRSRAN_API int srsran_carrier_to_cell(const srsran_carrier_nr_t* carrier, srsran_cell_t* cell); SRSRAN_API int srsran_carrier_to_cell(const srsran_carrier_nr_t* carrier, srsran_cell_t* cell);
/** /**
* @brief Writes Channel State Information measurement into a string * @brief Writes detailed Channel State Information measurement into a string
* @param meas Provides the measurement * @param meas Provides the measurement
* @param str Provides string * @param str Provides string
* @param str_len Maximum string length * @param str_len Maximum string length
@ -662,6 +662,15 @@ SRSRAN_API int srsran_carrier_to_cell(const srsran_carrier_nr_t* carrier, srsran
*/ */
SRSRAN_API uint32_t srsran_csi_meas_info(const srsran_csi_trs_measurements_t* meas, char* str, uint32_t str_len); SRSRAN_API uint32_t srsran_csi_meas_info(const srsran_csi_trs_measurements_t* meas, char* str, uint32_t str_len);
/**
* @brief Writes short Channel State Information measurement into a string
* @param meas Provides the measurement
* @param str Provides string
* @param str_len Maximum string length
* @return The number of writen characters
*/
SRSRAN_API uint32_t srsran_csi_meas_info_short(const srsran_csi_trs_measurements_t* meas, char* str, uint32_t str_len);
/** /**
* @brief Converts a given string into a subcarrier spacing * @brief Converts a given string into a subcarrier spacing
* @param str Provides the string * @param str Provides the string
@ -704,6 +713,20 @@ SRSRAN_API int srsran_coreset_zero(uint32_t n_cell_id,
uint32_t idx, uint32_t idx,
srsran_coreset_t* coreset); srsran_coreset_t* coreset);
/**
* @brief Convert SSB pattern to string
* @param pattern
* @return a string describing the SSB pattern
*/
SRSRAN_API const char* srsran_ssb_pattern_to_str(srsran_ssb_patern_t pattern);
/**
* @brief Convert string to SSB pattern
* @param str String to convert
* @return The pattern, SRSRAN_SSB_PATTERN_INVALID if string is invalid
*/
SRSRAN_API srsran_ssb_patern_t srsran_ssb_pattern_fom_str(const char* str);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

@ -30,6 +30,7 @@
typedef struct SRSRAN_API { typedef struct SRSRAN_API {
srsran_pusch_nr_args_t pusch; srsran_pusch_nr_args_t pusch;
srsran_pucch_nr_args_t pucch; srsran_pucch_nr_args_t pucch;
float pusch_min_snr_dB; ///< Minimum SNR threshold to decode PUSCH, set to 0 for default value
uint32_t nof_max_prb; uint32_t nof_max_prb;
} srsran_gnb_ul_args_t; } srsran_gnb_ul_args_t;
@ -45,6 +46,7 @@ typedef struct SRSRAN_API {
srsran_dmrs_sch_t dmrs; srsran_dmrs_sch_t dmrs;
srsran_chest_dl_res_t chest_pusch; srsran_chest_dl_res_t chest_pusch;
srsran_chest_ul_res_t chest_pucch; srsran_chest_ul_res_t chest_pucch;
float pusch_min_snr_dB; ///< Minimum measured DMRS SNR, below this threshold PUSCH is not decoded
} srsran_gnb_ul_t; } srsran_gnb_ul_t;
SRSRAN_API int srsran_gnb_ul_init(srsran_gnb_ul_t* q, cf_t* input, const srsran_gnb_ul_args_t* args); SRSRAN_API int srsran_gnb_ul_init(srsran_gnb_ul_t* q, cf_t* input, const srsran_gnb_ul_args_t* args);
@ -72,6 +74,7 @@ SRSRAN_API int srsran_gnb_ul_get_pucch(srsran_gnb_ul_t* q,
SRSRAN_API uint32_t srsran_gnb_ul_pucch_info(srsran_gnb_ul_t* q, SRSRAN_API uint32_t srsran_gnb_ul_pucch_info(srsran_gnb_ul_t* q,
const srsran_pucch_nr_resource_t* resource, const srsran_pucch_nr_resource_t* resource,
const srsran_uci_data_nr_t* uci_data, const srsran_uci_data_nr_t* uci_data,
const srsran_csi_trs_measurements_t* csi,
char* str, char* str,
uint32_t str_len); uint32_t str_len);

@ -40,18 +40,26 @@ srsran_csi_new_nzp_csi_rs_measurement(const srsran_csi_hl_resource_cfg_t csi_res
uint32_t nzp_csi_rs_id); uint32_t nzp_csi_rs_id);
/** /**
* @brief Generates CSI report configuration and values from the higher layer configuration and a list of measurements * @brief Generates CSI report configuration from the higher layer configuration for a given slot
* @param cfg Higher layer report configuration * @param cfg Higher layer report configuration
* @param slot_idx Slot index within the radio frame * @param slot_cfg Current slot configuration
* @param measurements Filtered CSI measurements * @param[out] report_cfg Report configuration for the given slot
* @param[out] report_cfg Report configuration re * @return The number CSI reports for transmission if the provided data is valid, SRSRAN_ERROR code otherwise
*/
SRSRAN_API int srsran_csi_reports_generate(const srsran_csi_hl_cfg_t* cfg,
const srsran_slot_cfg_t* slot_cfg,
srsran_csi_report_cfg_t report_cfg[SRSRAN_CSI_MAX_NOF_REPORT]);
/**
* @brief Quantifies a given set of CSI reports from the given set of measurements
* @param reports Set of report configuration
* @param measurements Set of measurements to quantify
* @param report_value Set of report values
* @return The number CSI reports for transmission if the provided data is valid, SRSRAN_ERROR code otherwise * @return The number CSI reports for transmission if the provided data is valid, SRSRAN_ERROR code otherwise
*/ */
SRSRAN_API int SRSRAN_API int
srsran_csi_generate_reports(const srsran_csi_hl_cfg_t* cfg, srsran_csi_reports_quantify(const srsran_csi_report_cfg_t reports[SRSRAN_CSI_MAX_NOF_REPORT],
uint32_t slot_idx,
const srsran_csi_channel_measurements_t measurements[SRSRAN_CSI_MAX_NOF_RESOURCES], const srsran_csi_channel_measurements_t measurements[SRSRAN_CSI_MAX_NOF_RESOURCES],
srsran_csi_report_cfg_t report_cfg[SRSRAN_CSI_MAX_NOF_REPORT],
srsran_csi_report_value_t report_value[SRSRAN_CSI_MAX_NOF_REPORT]); srsran_csi_report_value_t report_value[SRSRAN_CSI_MAX_NOF_REPORT]);
/** /**

@ -171,12 +171,10 @@ typedef struct SRSRAN_API {
/** /**
* @brief CSI report configuration * @brief CSI report configuration
* @note An unset report is marked with `cfg.type = SRSRAN_CSI_REPORT_TYPE_NONE`
*/ */
typedef struct SRSRAN_API { typedef struct SRSRAN_API {
srsran_csi_report_type_t type; ///< CSI report type (none, periodic, semiPersistentOnPUCCH, ...) srsran_csi_hl_report_cfg_t cfg; ///< Higher layer CSI report configuration
srsran_csi_report_quantity_t quantity; ///< Report quantity
srsran_pucch_nr_resource_t pucch_resource; ///< PUCCH resource to use for periodic reporting
srsran_csi_report_freq_t freq_cfg; ///< Determine whether it is wideband or subband
// Resource set context // Resource set context
uint32_t nof_ports; ///< Number of antenna ports uint32_t nof_ports; ///< Number of antenna ports
@ -202,7 +200,6 @@ typedef struct SRSRAN_API {
void* none; void* none;
srsran_csi_report_wideband_cri_ri_pmi_cqi_t wideband_cri_ri_pmi_cqi; srsran_csi_report_wideband_cri_ri_pmi_cqi_t wideband_cri_ri_pmi_cqi;
}; };
bool valid; ///< Used by receiver only
} srsran_csi_report_value_t; } srsran_csi_report_value_t;
/** /**

@ -28,8 +28,11 @@ typedef struct SRSRAN_API {
srsran_mcs_table_t mcs_table; ///< @brief Indicates the MCS table the UE shall use for PDSCH and/or PUSCH without srsran_mcs_table_t mcs_table; ///< @brief Indicates the MCS table the UE shall use for PDSCH and/or PUSCH without
///< transform precoding ///< transform precoding
srsran_xoverhead_t xoverhead; ///< Accounts for overhead from CSI-RS, CORESET, etc. If the field is absent, the UE srsran_xoverhead_t xoverhead; ///< @brief Accounts for overhead from CSI-RS, CORESET, etc. If the field is absent, the
///< applies value xOh0 (see TS 38.214 [19], clause 5.1.3.2). ///< UE applies value xOh0 (see TS 38.214 [19], clause 5.1.3.2).
bool limited_buffer_rm; ///< @brief Enables LBRM (Limited buffer rate-matching). Given by rateMatching parameter in
///< PUSCH-ServingCellConfig or PDSCH-ServingCellConfig ASN1 sequences
} srsran_sch_cfg_t; } srsran_sch_cfg_t;
typedef struct SRSRAN_API { typedef struct SRSRAN_API {

@ -121,7 +121,7 @@ SRSRAN_API int srsran_ue_dl_nr_decode_pdsch(srsran_ue_dl_nr_t* q,
const srsran_sch_cfg_nr_t* cfg, const srsran_sch_cfg_nr_t* cfg,
srsran_pdsch_res_nr_t* res); srsran_pdsch_res_nr_t* res);
SRSRAN_API int srsran_ue_dl_nr_pdsch_info(const srsran_ue_dl_nr_t* q, SRSRAN_API uint32_t srsran_ue_dl_nr_pdsch_info(const srsran_ue_dl_nr_t* q,
const srsran_sch_cfg_nr_t* cfg, const srsran_sch_cfg_nr_t* cfg,
const srsran_pdsch_res_nr_t res[SRSRAN_MAX_CODEWORDS], const srsran_pdsch_res_nr_t res[SRSRAN_MAX_CODEWORDS],
char* str, char* str,

@ -113,7 +113,7 @@ private:
bool decimator_busy = false; ///< Indicates the decimator is changing the rate bool decimator_busy = false; ///< Indicates the decimator is changing the rate
rf_timestamp_t end_of_burst_time = {}; rf_timestamp_t end_of_burst_time = {};
bool is_start_of_burst = false; std::atomic<bool> is_start_of_burst{false};
uint32_t tx_adv_nsamples = 0; uint32_t tx_adv_nsamples = 0;
double tx_adv_sec = 0.0; // Transmission time advance to compensate for antenna->timestamp delay double tx_adv_sec = 0.0; // Transmission time advance to compensate for antenna->timestamp delay
bool tx_adv_auto = false; bool tx_adv_auto = false;

@ -22,10 +22,10 @@
#ifndef SRSUE_RRC_COMMON_H #ifndef SRSUE_RRC_COMMON_H
#define SRSUE_RRC_COMMON_H #define SRSUE_RRC_COMMON_H
namespace srsran {
#include <stdint.h> #include <stdint.h>
namespace srsran {
enum quant_s { quant_rsrp, quant_rsrq }; enum quant_s { quant_rsrp, quant_rsrq };
uint8_t rrc_value_to_range(quant_s quant, const float value); uint8_t rrc_value_to_range(quant_s quant, const float value);

@ -0,0 +1,25 @@
/**
*
* \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 SRSRAN_EMERGENCY_HANDLERS_H
#define SRSRAN_EMERGENCY_HANDLERS_H
using emergency_cleanup_callback = void (*)(void*);
// Add a cleanup function to be called when a kill signal is about to be delivered to the process. The handler may
// optionally pass a pointer to identify what instance of the handler is being called.
void add_emergency_cleanup_handler(emergency_cleanup_callback callback, void* data);
// Executes all registered emergency cleanup handlers.
void execute_emergency_cleanup_handlers();
#endif // SRSRAN_EMERGENCY_HANDLERS_H

@ -0,0 +1,27 @@
/**
*
* \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.
*
*/
/**
* @file signal_handler.h
* @brief Common signal handling methods for all srsRAN applications.
*/
#ifndef SRSRAN_SIGNAL_HANDLER_H
#define SRSRAN_SIGNAL_HANDLER_H
using srsran_signal_hanlder = void (*)();
/// Registers the specified function to be called when the user interrupts the program execution (eg: via Ctrl+C).
/// Passing a null function pointer disables the current installed handler.
void srsran_register_signal_handler(srsran_signal_hanlder handler);
#endif // SRSRAN_SIGNAL_HANDLER_H

@ -27,4 +27,5 @@ add_subdirectory(rlc)
add_subdirectory(pdcp) add_subdirectory(pdcp)
add_subdirectory(gtpu) add_subdirectory(gtpu)
add_subdirectory(srslog) add_subdirectory(srslog)
add_subdirectory(support)
add_subdirectory(system) add_subdirectory(system)

@ -387,15 +387,20 @@ bool make_phy_search_space_cfg(const search_space_s& search_space, srsran_search
} }
srsran_search_space.coreset_id = search_space.ctrl_res_set_id; srsran_search_space.coreset_id = search_space.ctrl_res_set_id;
srsran_search_space.duration = 1;
if (search_space.dur_present) {
srsran_search_space.duration = search_space.dur;
}
if (not search_space.nrof_candidates_present) { if (not search_space.nrof_candidates_present) {
asn1::log_warning("nrof_candidates_present option not present"); asn1::log_warning("nrof_candidates_present option not present");
return false; return false;
} }
srsran_search_space.nof_candidates[0] = search_space.nrof_candidates.aggregation_level1.value; srsran_search_space.nof_candidates[0] = search_space.nrof_candidates.aggregation_level1.to_number();
srsran_search_space.nof_candidates[1] = search_space.nrof_candidates.aggregation_level2.value; srsran_search_space.nof_candidates[1] = search_space.nrof_candidates.aggregation_level2.to_number();
srsran_search_space.nof_candidates[2] = search_space.nrof_candidates.aggregation_level4.value; srsran_search_space.nof_candidates[2] = search_space.nrof_candidates.aggregation_level4.to_number();
srsran_search_space.nof_candidates[3] = search_space.nrof_candidates.aggregation_level8.value; srsran_search_space.nof_candidates[3] = search_space.nrof_candidates.aggregation_level8.to_number();
srsran_search_space.nof_candidates[4] = search_space.nrof_candidates.aggregation_level16.value; srsran_search_space.nof_candidates[4] = search_space.nrof_candidates.aggregation_level16.to_number();
if (not search_space.search_space_type_present) { if (not search_space.search_space_type_present) {
asn1::log_warning("nrof_candidates option not present"); asn1::log_warning("nrof_candidates option not present");
@ -1484,19 +1489,22 @@ bool make_phy_ssb_cfg(const srsran_carrier_nr_t& carrier,
return true; return true;
} }
bool make_pdsch_cfg_from_serv_cell(asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_sch_hl_cfg_nr_t* sch_hl) bool make_pdsch_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_sch_hl_cfg_nr_t* sch_hl)
{ {
if (serv_cell.csi_meas_cfg_present and if (serv_cell.csi_meas_cfg_present and
serv_cell.csi_meas_cfg.type().value == serv_cell.csi_meas_cfg.type().value ==
setup_release_c< ::asn1::rrc_nr::csi_meas_cfg_s>::types_opts::options::setup) { setup_release_c< ::asn1::rrc_nr::csi_meas_cfg_s>::types_opts::options::setup) {
auto& setup = serv_cell.csi_meas_cfg.setup(); auto& setup = serv_cell.csi_meas_cfg.setup();
// Configure NZP-CSI
if (setup.nzp_csi_rs_res_set_to_add_mod_list_present) { if (setup.nzp_csi_rs_res_set_to_add_mod_list_present) {
for (auto& nzp_set : setup.nzp_csi_rs_res_set_to_add_mod_list) { for (auto& nzp_set : setup.nzp_csi_rs_res_set_to_add_mod_list) {
auto& uecfg_set = sch_hl->nzp_csi_rs_sets[nzp_set.nzp_csi_res_set_id]; auto& uecfg_set = sch_hl->nzp_csi_rs_sets[nzp_set.nzp_csi_res_set_id];
uecfg_set.trs_info = nzp_set.trs_info_present; uecfg_set.trs_info = nzp_set.trs_info_present;
uecfg_set.count = nzp_set.nzp_csi_rs_res.size(); uecfg_set.count = nzp_set.nzp_csi_rs_res.size();
uint32_t count = 0;
for (uint8_t nzp_rs_idx : nzp_set.nzp_csi_rs_res) { for (uint8_t nzp_rs_idx : nzp_set.nzp_csi_rs_res) {
auto& res = uecfg_set.data[nzp_rs_idx]; auto& res = uecfg_set.data[count++];
if (not srsran::make_phy_nzp_csi_rs_resource(setup.nzp_csi_rs_res_to_add_mod_list[nzp_rs_idx], &res)) { if (not srsran::make_phy_nzp_csi_rs_resource(setup.nzp_csi_rs_res_to_add_mod_list[nzp_rs_idx], &res)) {
return false; return false;
} }
@ -1524,6 +1532,77 @@ bool make_pdsch_cfg_from_serv_cell(asn1::rrc_nr::serving_cell_cfg_s& serv_cell,
return true; return true;
} }
bool make_csi_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_csi_hl_cfg_t* csi_hl)
{
if (serv_cell.csi_meas_cfg_present and
serv_cell.csi_meas_cfg.type().value ==
setup_release_c< ::asn1::rrc_nr::csi_meas_cfg_s>::types_opts::options::setup) {
auto& setup = serv_cell.csi_meas_cfg.setup();
// Configure CSI-Report
if (setup.csi_report_cfg_to_add_mod_list_present) {
for (uint32_t i = 0; i < setup.csi_report_cfg_to_add_mod_list.size(); ++i) {
const auto& csi_rep = setup.csi_report_cfg_to_add_mod_list[i];
if (not make_phy_csi_report(csi_rep, &csi_hl->reports[i])) {
return false;
}
}
}
}
return true;
}
bool make_duplex_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_common_s& serv_cell,
srsran_duplex_config_nr_t* duplex_cfg)
{
duplex_cfg->mode = serv_cell.tdd_ul_dl_cfg_common_present ? SRSRAN_DUPLEX_MODE_TDD : SRSRAN_DUPLEX_MODE_FDD;
if (serv_cell.tdd_ul_dl_cfg_common_present) {
if (not make_phy_tdd_cfg(serv_cell.tdd_ul_dl_cfg_common, duplex_cfg)) {
return false;
}
}
return true;
}
bool fill_phy_pdcch_cfg(const asn1::rrc_nr::pdcch_cfg_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch)
{
if (pdcch_cfg.ctrl_res_set_to_add_mod_list_present) {
for (const ctrl_res_set_s& coreset : pdcch_cfg.ctrl_res_set_to_add_mod_list) {
pdcch->coreset_present[coreset.ctrl_res_set_id] = true;
make_phy_coreset_cfg(coreset, &pdcch->coreset[coreset.ctrl_res_set_id]);
}
}
if (pdcch_cfg.search_spaces_to_add_mod_list_present) {
for (const search_space_s& ss : pdcch_cfg.search_spaces_to_add_mod_list) {
pdcch->search_space_present[ss.search_space_id] = true;
make_phy_search_space_cfg(ss, &pdcch->search_space[ss.search_space_id]);
}
}
return true;
}
bool fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch)
{
if (pdcch_cfg.common_ctrl_res_set_present) {
pdcch->coreset_present[pdcch_cfg.common_ctrl_res_set.ctrl_res_set_id] = true;
make_phy_coreset_cfg(pdcch_cfg.common_ctrl_res_set, &pdcch->coreset[pdcch_cfg.common_ctrl_res_set.ctrl_res_set_id]);
}
if (pdcch_cfg.common_search_space_list_present) {
for (const search_space_s& ss : pdcch_cfg.common_search_space_list) {
pdcch->search_space_present[ss.search_space_id] = true;
make_phy_search_space_cfg(ss, &pdcch->search_space[ss.search_space_id]);
if (pdcch_cfg.ra_search_space_present and pdcch_cfg.ra_search_space == ss.search_space_id) {
pdcch->ra_search_space_present = true;
pdcch->ra_search_space = pdcch->search_space[ss.search_space_id];
}
}
}
return true;
}
} // namespace srsran } // namespace srsran
namespace srsenb { namespace srsenb {

@ -59,7 +59,7 @@ add_dependencies(srsran_common gen_build_info)
add_executable(arch_select arch_select.cc) add_executable(arch_select arch_select.cc)
target_include_directories(srsran_common PUBLIC ${SEC_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ${BACKWARD_INCLUDE_DIRS}) target_include_directories(srsran_common PUBLIC ${SEC_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ${BACKWARD_INCLUDE_DIRS})
target_link_libraries(srsran_common srsran_phy srslog ${SEC_LIBRARIES} ${BACKWARD_LIBRARIES} ${SCTP_LIBRARIES}) target_link_libraries(srsran_common srsran_phy support srslog ${SEC_LIBRARIES} ${BACKWARD_LIBRARIES} ${SCTP_LIBRARIES})
target_compile_definitions(srsran_common PRIVATE ${BACKWARD_DEFINITIONS}) target_compile_definitions(srsran_common PRIVATE ${BACKWARD_DEFINITIONS})
INSTALL(TARGETS srsran_common DESTINATION ${LIBRARY_DIR}) INSTALL(TARGETS srsran_common DESTINATION ${LIBRARY_DIR})

@ -67,7 +67,7 @@ ue_bearer_manager_impl::radio_bearer_t ue_bearer_manager_impl::get_radio_bearer(
return it != bearers.end() ? it->second : invalid_rb; return it != bearers.end() ? it->second : invalid_rb;
} }
ue_bearer_manager_impl::radio_bearer_t ue_bearer_manager_impl::get_lcid_bearer(uint32_t lcid) ue_bearer_manager_impl::radio_bearer_t ue_bearer_manager_impl::get_eps_bearer_id_for_lcid(uint32_t lcid)
{ {
auto lcid_it = lcid_to_eps_bearer_id.find(lcid); auto lcid_it = lcid_to_eps_bearer_id.find(lcid);
return lcid_it != lcid_to_eps_bearer_id.end() ? bearers.at(lcid_it->second) : invalid_rb; return lcid_it != lcid_to_eps_bearer_id.end() ? bearers.at(lcid_it->second) : invalid_rb;
@ -188,7 +188,7 @@ enb_bearer_manager::radio_bearer_t enb_bearer_manager::get_lcid_bearer(uint16_t
if (user_it == users_map.end()) { if (user_it == users_map.end()) {
return srsran::detail::ue_bearer_manager_impl::invalid_rb; return srsran::detail::ue_bearer_manager_impl::invalid_rb;
} }
return user_it->second.get_lcid_bearer(lcid); return user_it->second.get_eps_bearer_id_for_lcid(lcid);
} }
enb_bearer_manager::radio_bearer_t enb_bearer_manager::get_radio_bearer(uint16_t rnti, uint32_t eps_bearer_id) enb_bearer_manager::radio_bearer_t enb_bearer_manager::get_radio_bearer(uint16_t rnti, uint32_t eps_bearer_id)

@ -22,11 +22,21 @@
#include "srsran/common/mac_pcap_base.h" #include "srsran/common/mac_pcap_base.h"
#include "srsran/config.h" #include "srsran/config.h"
#include "srsran/phy/common/phy_common.h" #include "srsran/phy/common/phy_common.h"
#include "srsran/support/emergency_handlers.h"
#include <stdint.h> #include <stdint.h>
namespace srsran { namespace srsran {
mac_pcap_base::mac_pcap_base() : logger(srslog::fetch_basic_logger("MAC")), thread("PCAP_WRITER_MAC") {} /// Try to flush the contents of the pcap class before the application is killed.
static void emergency_cleanup_handler(void* data)
{
reinterpret_cast<mac_pcap_base*>(data)->close();
}
mac_pcap_base::mac_pcap_base() : logger(srslog::fetch_basic_logger("MAC")), thread("PCAP_WRITER_MAC")
{
add_emergency_cleanup_handler(emergency_cleanup_handler, this);
}
mac_pcap_base::~mac_pcap_base() {} mac_pcap_base::~mac_pcap_base() {}

@ -316,7 +316,10 @@ bool phy_cfg_nr_t::get_uci_cfg(const srsran_slot_cfg_t& slot_cfg,
} }
// Generate configuration for CSI reports // Generate configuration for CSI reports
// ... n = srsran_csi_reports_generate(&csi, &slot_cfg, uci_cfg.csi);
if (n > SRSRAN_SUCCESS) {
uci_cfg.nof_csi = (uint32_t)n;
}
return true; return true;
} }

@ -393,10 +393,13 @@ void phy_cfg_nr_default_t::make_harq_auto(srsran_harq_ack_cfg_hl_t& harq,
void phy_cfg_nr_default_t::make_prach_default_lte(srsran_prach_cfg_t& prach) void phy_cfg_nr_default_t::make_prach_default_lte(srsran_prach_cfg_t& prach)
{ {
prach.is_nr = true;
prach.config_idx = 0; prach.config_idx = 0;
prach.freq_offset = 4;
prach.root_seq_idx = 0; prach.root_seq_idx = 0;
prach.is_nr = true; prach.zero_corr_zone = 0;
prach.freq_offset = 4;
prach.num_ra_preambles = 64;
prach.hs_flag = false;
} }
phy_cfg_nr_default_t::phy_cfg_nr_default_t(const reference_cfg_t& reference_cfg) phy_cfg_nr_default_t::phy_cfg_nr_default_t(const reference_cfg_t& reference_cfg)
@ -428,9 +431,11 @@ phy_cfg_nr_default_t::phy_cfg_nr_default_t(const reference_cfg_t& reference_cfg)
if (duplex.mode == SRSRAN_DUPLEX_MODE_TDD) { if (duplex.mode == SRSRAN_DUPLEX_MODE_TDD) {
carrier.dl_center_frequency_hz = 3513.6e6; carrier.dl_center_frequency_hz = 3513.6e6;
carrier.ul_center_frequency_hz = 3513.6e6;
ssb.scs = srsran_subcarrier_spacing_30kHz; ssb.scs = srsran_subcarrier_spacing_30kHz;
} else { } else {
carrier.dl_center_frequency_hz = 881.5e6; carrier.dl_center_frequency_hz = 881.5e6;
carrier.ul_center_frequency_hz = 836.6e6;
ssb.scs = srsran_subcarrier_spacing_15kHz; ssb.scs = srsran_subcarrier_spacing_15kHz;
} }
carrier.ssb_center_freq_hz = carrier.dl_center_frequency_hz; carrier.ssb_center_freq_hz = carrier.dl_center_frequency_hz;
@ -479,6 +484,24 @@ phy_cfg_nr_default_t::phy_cfg_nr_default_t(const reference_cfg_t& reference_cfg)
} }
prach.tdd_config.configured = (duplex.mode == SRSRAN_DUPLEX_MODE_TDD); prach.tdd_config.configured = (duplex.mode == SRSRAN_DUPLEX_MODE_TDD);
// Make default CSI report configuration always
csi.reports[0].channel_meas_id = 0;
csi.reports[0].type = SRSRAN_CSI_REPORT_TYPE_PERIODIC;
csi.reports[0].periodic.period = 20;
csi.reports[0].periodic.offset = 9;
csi.reports[0].periodic.resource.format = SRSRAN_PUCCH_NR_FORMAT_2;
csi.reports[0].periodic.resource.starting_prb = 51;
csi.reports[0].periodic.resource.format = SRSRAN_PUCCH_NR_FORMAT_2;
csi.reports[0].periodic.resource.nof_prb = 1;
csi.reports[0].periodic.resource.nof_symbols = 2;
csi.reports[0].periodic.resource.start_symbol_idx = 10;
csi.reports[0].quantity = SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI;
csi.reports[0].cqi_table = SRSRAN_CSI_CQI_TABLE_1;
csi.reports[0].freq_cfg = SRSRAN_CSI_REPORT_FREQ_WIDEBAND;
csi.csi_resources[0].type = srsran_csi_hl_resource_cfg_t::SRSRAN_CSI_HL_RESOURCE_CFG_TYPE_NZP_CSI_RS_SSB;
csi.csi_resources[0].nzp_csi_rs_ssb.nzp_csi_rs_resource_set_id_list[0] = 0;
csi.csi_resources[0].nzp_csi_rs_ssb.nzp_csi_rs_resource_set_id_list_count = 1;
} }
} // namespace srsran } // namespace srsran

@ -22,10 +22,22 @@
#include "srsran/common/s1ap_pcap.h" #include "srsran/common/s1ap_pcap.h"
#include "srsran/common/pcap.h" #include "srsran/common/pcap.h"
#include "srsran/srsran.h" #include "srsran/srsran.h"
#include "srsran/support/emergency_handlers.h"
#include <stdint.h> #include <stdint.h>
namespace srsran { namespace srsran {
/// Try to flush the contents of the pcap class before the application is killed.
static void emergency_cleanup_handler(void* data)
{
reinterpret_cast<s1ap_pcap*>(data)->close();
}
s1ap_pcap::s1ap_pcap()
{
add_emergency_cleanup_handler(emergency_cleanup_handler, this);
}
void s1ap_pcap::enable() void s1ap_pcap::enable()
{ {
enable_write = true; enable_write = true;
@ -38,6 +50,9 @@ void s1ap_pcap::open(const char* filename_)
} }
void s1ap_pcap::close() void s1ap_pcap::close()
{ {
if (!enable_write) {
return;
}
fprintf(stdout, "Saving S1AP PCAP file (DLT=%d) to %s\n", S1AP_LTE_DLT, filename.c_str()); fprintf(stdout, "Saving S1AP PCAP file (DLT=%d) to %s\n", S1AP_LTE_DLT, filename.c_str());
DLT_PCAP_Close(pcap_file); DLT_PCAP_Close(pcap_file);
} }

@ -42,27 +42,31 @@ int bands_test_nr()
// n32 n75 // n32 n75
TESTASSERT(bands.nr_arfcn_to_freq(290400) == 1452.0e6); TESTASSERT(bands.nr_arfcn_to_freq(290400) == 1452.0e6);
TESTASSERT(bands.nr_arfcn_to_freq(294400) == 1472.0e6); TESTASSERT(bands.nr_arfcn_to_freq(294400) == 1472.0e6);
// n5
TESTASSERT(bands.get_duplex_mode(5) == SRSRAN_DUPLEX_MODE_FDD);
TESTASSERT(bands.nr_arfcn_to_freq(176300) == 881.5e6);
TESTASSERT(bands.freq_to_nr_arfcn(881.5e6) == 176300);
TESTASSERT(bands.get_ul_arfcn_from_dl_arfcn(176300) == 167300);
TESTASSERT(bands.nr_arfcn_to_freq(167300) == 836.5e6);
// check actual freqs for FDD carrier (example values are for 52 PRB) // check actual freqs for FDD carrier (example values are for 52 PRB)
TESTASSERT(bands.get_center_freq_from_abs_freq_point_a(52, 175364) == 881.5e6); TESTASSERT(bands.get_center_freq_from_abs_freq_point_a(52, 175364) == 881.5e6);
TESTASSERT(bands.get_center_freq_from_abs_freq_point_a(52, 166364) == 836.5e6); TESTASSERT(bands.get_center_freq_from_abs_freq_point_a(52, 166364) == 836.5e6);
// n3
TESTASSERT(bands.nr_arfcn_to_freq(342000) == 1710.0e6);
TESTASSERT(bands.nr_arfcn_to_freq(348000) == 1740.0e6);
TESTASSERT(bands.nr_arfcn_to_freq(361000) == 1805.0e6);
TESTASSERT(bands.nr_arfcn_to_freq(376000) == 1880.0e6);
// n1 // n1
TESTASSERT(bands.nr_arfcn_to_freq(384000) == 1920.0e6); TESTASSERT(bands.nr_arfcn_to_freq(384000) == 1920.0e6);
TESTASSERT(bands.nr_arfcn_to_freq(388030) == 1940.15e6); TESTASSERT(bands.nr_arfcn_to_freq(388030) == 1940.15e6);
TESTASSERT(bands.nr_arfcn_to_freq(391830) == 1959.15e6); TESTASSERT(bands.nr_arfcn_to_freq(391830) == 1959.15e6);
TESTASSERT(bands.nr_arfcn_to_freq(434000) == 2170.0e6); TESTASSERT(bands.nr_arfcn_to_freq(434000) == 2170.0e6);
// n3
TESTASSERT(bands.get_duplex_mode(3) == SRSRAN_DUPLEX_MODE_FDD);
TESTASSERT(bands.nr_arfcn_to_freq(342000) == 1710.0e6);
TESTASSERT(bands.nr_arfcn_to_freq(348000) == 1740.0e6);
TESTASSERT(bands.nr_arfcn_to_freq(361000) == 1805.0e6);
TESTASSERT(bands.nr_arfcn_to_freq(376000) == 1880.0e6);
TESTASSERT(bands.get_abs_freq_point_a_arfcn(52, 368500) == 367564);
TESTASSERT(bands.get_abs_freq_ssb_arfcn(3, srsran_subcarrier_spacing_15kHz, 367564) > 367924);
// n5
TESTASSERT(bands.get_duplex_mode(5) == SRSRAN_DUPLEX_MODE_FDD);
TESTASSERT(bands.nr_arfcn_to_freq(176300) == 881.5e6);
TESTASSERT(bands.freq_to_nr_arfcn(881.5e6) == 176300);
TESTASSERT(bands.get_ul_arfcn_from_dl_arfcn(176300) == 167300);
TESTASSERT(bands.nr_arfcn_to_freq(167300) == 836.5e6);
TESTASSERT(bands.get_abs_freq_point_a_arfcn(52, 176300) == 175364);
TESTASSERT(bands.get_abs_freq_ssb_arfcn(5, srsran_subcarrier_spacing_15kHz, 175364) > 175724);
// n7 n38 // n7 n38
TESTASSERT(bands.get_duplex_mode(7) == SRSRAN_DUPLEX_MODE_FDD); TESTASSERT(bands.get_duplex_mode(7) == SRSRAN_DUPLEX_MODE_FDD);
TESTASSERT(bands.nr_arfcn_to_freq(500000) == 2500.0e6); TESTASSERT(bands.nr_arfcn_to_freq(500000) == 2500.0e6);

@ -401,6 +401,75 @@ void task_thread_pool::worker_t::run_thread()
running = false; running = false;
} }
task_worker::task_worker(std::string thread_name_,
uint32_t queue_size,
bool start_deferred,
int32_t prio_,
uint32_t mask_) :
thread(std::move(thread_name_)),
prio(prio_),
mask(mask_),
pending_tasks(queue_size),
logger(srslog::fetch_basic_logger("POOL"))
{
if (not start_deferred) {
start(prio_, mask_);
}
}
task_worker::~task_worker()
{
stop();
}
void task_worker::stop()
{
if (not pending_tasks.is_stopped()) {
pending_tasks.stop();
wait_thread_finish();
}
}
void task_worker::start(int32_t prio_, uint32_t mask_)
{
prio = prio_;
mask = mask_;
if (mask == 255) {
thread::start(prio);
} else {
thread::start_cpu_mask(prio, mask);
}
}
void task_worker::push_task(task_t&& task)
{
auto ret = pending_tasks.try_push(std::move(task));
if (ret.is_error()) {
logger.error("Cannot push anymore tasks into the worker queue. maximum size is %u",
uint32_t(pending_tasks.max_size()));
return;
}
}
uint32_t task_worker::nof_pending_tasks() const
{
return pending_tasks.size();
}
void task_worker::run_thread()
{
while (true) {
bool success;
task_t task = pending_tasks.pop_blocking(&success);
if (not success) {
break;
}
task();
}
logger.info("Task worker %s finished.", thread::get_name().c_str());
}
// Global thread pool for long, low-priority tasks // Global thread pool for long, low-priority tasks
task_thread_pool& get_background_workers() task_thread_pool& get_background_workers()
{ {

@ -224,6 +224,7 @@ int mac_rar_pdu_nr::init_tx(byte_buffer_t* buffer_, uint32_t pdu_len_)
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
buffer = buffer_; buffer = buffer_;
buffer->N_bytes = 0;
subpdus.clear(); subpdus.clear();
pdu_len = pdu_len_; pdu_len = pdu_len_;
remaining_len = pdu_len_; remaining_len = pdu_len_;

@ -34,8 +34,18 @@ mac_sch_subpdu_nr::nr_lcid_sch_t mac_sch_subpdu_nr::get_type()
bool mac_sch_subpdu_nr::is_sdu() bool mac_sch_subpdu_nr::is_sdu()
{ {
// for UL-SCH LCID 52 is also valid for carrying SDUs return (lcid <= 32);
return (lcid <= 32 || (parent->is_ulsch() && lcid == 52)); }
bool mac_sch_subpdu_nr::has_length_field()
{
// CCCH (both versions) don't have a length field in the UL
if (parent->is_ulsch()) {
if (lcid == CCCH_SIZE_48 || lcid == CCCH_SIZE_64) {
return false;
}
}
return (is_sdu() || is_var_len_ce(lcid));
} }
// returns false for all reserved values in Table 6.2.1-1 and 6.2.1-2 // returns false for all reserved values in Table 6.2.1-1 and 6.2.1-2
@ -44,10 +54,16 @@ bool mac_sch_subpdu_nr::is_valid_lcid()
return (lcid <= 63 && ((parent->is_ulsch() && (lcid <= 32 || lcid >= 52)) || (lcid <= 32 || lcid >= 47))); return (lcid <= 63 && ((parent->is_ulsch() && (lcid <= 32 || lcid >= 52)) || (lcid <= 32 || lcid >= 47)));
} }
bool mac_sch_subpdu_nr::is_var_len_ce() bool mac_sch_subpdu_nr::is_var_len_ce(uint32_t lcid)
{ {
switch (lcid) {
case LONG_TRUNC_BSR:
case LONG_BSR:
return true;
default:
return false; return false;
} }
}
// return length of PDU (or SRSRAN_ERROR otherwise) // return length of PDU (or SRSRAN_ERROR otherwise)
int32_t mac_sch_subpdu_nr::read_subheader(const uint8_t* ptr) int32_t mac_sch_subpdu_nr::read_subheader(const uint8_t* ptr)
@ -59,7 +75,7 @@ int32_t mac_sch_subpdu_nr::read_subheader(const uint8_t* ptr)
header_length = 1; header_length = 1;
if (is_valid_lcid()) { if (is_valid_lcid()) {
if ((is_sdu() || is_var_len_ce()) && not is_ul_ccch()) { if (has_length_field()) {
// Read first length byte // Read first length byte
sdu_length = (uint32_t)*ptr; sdu_length = (uint32_t)*ptr;
ptr++; ptr++;
@ -245,7 +261,7 @@ mac_sch_subpdu_nr::ta_t mac_sch_subpdu_nr::get_ta()
mac_sch_subpdu_nr::lcg_bsr_t mac_sch_subpdu_nr::get_sbsr() mac_sch_subpdu_nr::lcg_bsr_t mac_sch_subpdu_nr::get_sbsr()
{ {
lcg_bsr_t sbsr = {}; lcg_bsr_t sbsr = {};
if (parent->is_ulsch() && lcid == SHORT_BSR) { if (parent->is_ulsch() && (lcid == SHORT_BSR || lcid == SHORT_TRUNC_BSR)) {
uint8_t* ptr = sdu.ptr(); uint8_t* ptr = sdu.ptr();
sbsr.lcg_id = (ptr[0] & 0xe0) >> 5; sbsr.lcg_id = (ptr[0] & 0xe0) >> 5;
sbsr.buffer_size = ptr[0] & 0x1f; sbsr.buffer_size = ptr[0] & 0x1f;
@ -253,6 +269,44 @@ mac_sch_subpdu_nr::lcg_bsr_t mac_sch_subpdu_nr::get_sbsr()
return sbsr; return sbsr;
} }
mac_sch_subpdu_nr::lbsr_t mac_sch_subpdu_nr::get_lbsr()
{
lbsr_t lbsr = {};
lbsr.list.reserve(mac_sch_subpdu_nr::max_num_lcg_lbsr);
if (parent->is_ulsch() && (lcid == LONG_BSR || lcid == LONG_TRUNC_BSR)) {
uint8_t* ptr = sdu.ptr();
lbsr.bitmap = *ptr; // read LCG bitmap
ptr++; // skip LCG bitmap
// early stop if LBSR is empty
if (lbsr.bitmap == 0) {
return lbsr;
}
int bsr_cnt = 0;
for (int i = 0; i < mac_sch_subpdu_nr::max_num_lcg_lbsr; i++) {
// If LCGi bit is enabled, it means the next 8-bit BSR value corresponds to it
if (lbsr.bitmap & (0x1 << i)) {
lcg_bsr_t bsr = {};
bsr.lcg_id = i;
// For the Long truncated, some BSR words can be not present, assume BSR > 0 in that case
if (1 + bsr_cnt < sdu_length) {
bsr.buffer_size = ptr[bsr_cnt];
bsr_cnt++;
} else if (lcid == LONG_TRUNC_BSR) {
bsr.buffer_size = 63; // just assume it has 526 bytes to transmit
} else {
fprintf(stderr, "Error parsing LongBSR CE: sdu_length=%d but there are %d active bsr\n", sdu_length, bsr_cnt);
}
lbsr.list.push_back(bsr);
}
}
}
return lbsr;
}
uint32_t mac_sch_subpdu_nr::sizeof_ce(uint32_t lcid, bool is_ul) uint32_t mac_sch_subpdu_nr::sizeof_ce(uint32_t lcid, bool is_ul)
{ {
if (is_ul) { if (is_ul) {
@ -263,12 +317,14 @@ uint32_t mac_sch_subpdu_nr::sizeof_ce(uint32_t lcid, bool is_ul)
return 8; return 8;
case CRNTI: case CRNTI:
return 2; return 2;
case SHORT_TRUNC_BSR:
return 1;
case SHORT_BSR: case SHORT_BSR:
case SHORT_TRUNC_BSR:
return 1; return 1;
case SE_PHR: case SE_PHR:
return 2; return 2;
case LONG_BSR:
case LONG_TRUNC_BSR:
return 1; // minimum size, could be more than that
case PADDING: case PADDING:
return 0; return 0;
} }
@ -314,9 +370,13 @@ void mac_sch_subpdu_nr::to_string(fmt::memory_buffer& buffer)
lcg_bsr_t sbsr = get_sbsr(); lcg_bsr_t sbsr = get_sbsr();
fmt::format_to(buffer, " SBSR: lcg={} bs={}", sbsr.lcg_id, sbsr.buffer_size); fmt::format_to(buffer, " SBSR: lcg={} bs={}", sbsr.lcg_id, sbsr.buffer_size);
} break; } break;
case mac_sch_subpdu_nr::LONG_BSR: case mac_sch_subpdu_nr::LONG_BSR: {
fmt::format_to(buffer, " LBSR: len={}", get_total_length()); mac_sch_subpdu_nr::lbsr_t lbsr = get_lbsr();
break; fmt::format_to(buffer, " LBSR: bitmap={:#02x}", lbsr.bitmap);
for (const auto& lcg : lbsr.list) {
fmt::format_to(buffer, " lcg={} bs={}", lcg.lcg_id, lcg.buffer_size);
}
} break;
case mac_sch_subpdu_nr::SE_PHR: case mac_sch_subpdu_nr::SE_PHR:
fmt::format_to(buffer, " SE_PHR: ph={} pc={}", get_phr(), get_pcmax()); fmt::format_to(buffer, " SE_PHR: ph={} pc={}", get_phr(), get_pcmax());
break; break;
@ -430,13 +490,8 @@ uint32_t mac_sch_pdu_nr::size_header_sdu(const uint32_t lcid, const uint32_t nby
{ {
if (ulsch && (lcid == mac_sch_subpdu_nr::CCCH_SIZE_48 || lcid == mac_sch_subpdu_nr::CCCH_SIZE_64)) { if (ulsch && (lcid == mac_sch_subpdu_nr::CCCH_SIZE_48 || lcid == mac_sch_subpdu_nr::CCCH_SIZE_64)) {
return 1; return 1;
} else {
if (nbytes < 256) {
return 2;
} else {
return 3;
}
} }
return nbytes < 256 ? 2 : 3;
} }
uint32_t mac_sch_pdu_nr::get_remaing_len() uint32_t mac_sch_pdu_nr::get_remaing_len()

@ -481,10 +481,14 @@ void pdcp_entity_lte::update_rx_counts_queue(uint32_t rx_count)
rx_counts_info.pop_back(); rx_counts_info.pop_back();
fmc++; fmc++;
} }
if (not rx_counts_info.empty()) {
logger.debug("Queue too large. Updating. New FMC=%d, new back=%d, new queue_size=%zu", logger.debug("Queue too large. Updating. New FMC=%d, new back=%d, new queue_size=%zu",
fmc, fmc,
rx_counts_info.back(), rx_counts_info.back(),
rx_counts_info.size()); rx_counts_info.size());
} else {
logger.debug("Queue too large. Updating. New FMC=%d, new queue_size=%zu", fmc, rx_counts_info.size());
}
} }
if (rx_counts_info.empty()) { if (rx_counts_info.empty()) {

@ -23,6 +23,7 @@
#include "srsran/phy/common/sequence.h" #include "srsran/phy/common/sequence.h"
#include "srsran/phy/utils/debug.h" #include "srsran/phy/utils/debug.h"
#include "srsran/phy/utils/vector.h" #include "srsran/phy/utils/vector.h"
#include <complex.h>
// Implements TS 38.211 table 6.4.1.3.1.1-1: Number of DM-RS symbols and the corresponding N_PUCCH... // Implements TS 38.211 table 6.4.1.3.1.1-1: Number of DM-RS symbols and the corresponding N_PUCCH...
static uint32_t dmrs_pucch_format1_n_pucch(const srsran_pucch_nr_resource_t* resource, uint32_t m_prime) static uint32_t dmrs_pucch_format1_n_pucch(const srsran_pucch_nr_resource_t* resource, uint32_t m_prime)
@ -229,9 +230,10 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
float rsrp = 0.0f; float rsrp = 0.0f;
float epre = 0.0f; float epre = 0.0f;
float ta_err = 0.0f; float ta_err = 0.0f;
cf_t corr[SRSRAN_PUCCH_NR_FORMAT1_N_MAX] = {};
for (uint32_t m = 0; m < n_pucch; m++) { for (uint32_t m = 0; m < n_pucch; m++) {
cf_t corr = srsran_vec_acc_cc(ce[m], SRSRAN_NRE) / SRSRAN_NRE; corr[m] = srsran_vec_acc_cc(ce[m], SRSRAN_NRE) / SRSRAN_NRE;
rsrp += __real__ corr * __real__ corr + __imag__ corr * __imag__ corr; rsrp += SRSRAN_CSQABS(corr[m]);
epre += srsran_vec_avg_power_cf(ce[m], SRSRAN_NRE); epre += srsran_vec_avg_power_cf(ce[m], SRSRAN_NRE);
ta_err += srsran_vec_estimate_frequency(ce[m], SRSRAN_NRE); ta_err += srsran_vec_estimate_frequency(ce[m], SRSRAN_NRE);
} }
@ -263,7 +265,22 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
} }
// Measure CFO // Measure CFO
if (n_pucch > 1) {
float cfo_avg_hz = 0.0f;
for (uint32_t m = 0; m < n_pucch - 1; m++) {
uint32_t l0 = resource->start_symbol_idx + m * 2;
uint32_t l1 = resource->start_symbol_idx + (m + 1) * 2;
float time_diff = srsran_symbol_distance_s(l0, l1, q->carrier.scs);
float phase_diff = cargf(corr[m + 1] * conjf(corr[m]));
if (isnormal(time_diff)) {
cfo_avg_hz += phase_diff / (2.0f * M_PI * time_diff * (n_pucch - 1));
}
}
res->cfo_hz = cfo_avg_hz;
} else {
res->cfo_hz = NAN; // Not implemented res->cfo_hz = NAN; // Not implemented
}
// Do averaging here // Do averaging here
// ... Not implemented // ... Not implemented
@ -391,9 +408,10 @@ int srsran_dmrs_pucch_format2_estimate(const srsran_pucch_nr_t* q,
float epre = 0.0f; float epre = 0.0f;
float rsrp = 0.0f; float rsrp = 0.0f;
float ta_err = 0.0f; float ta_err = 0.0f;
cf_t corr[SRSRAN_PUCCH_NR_FORMAT2_MAX_NSYMB] = {};
for (uint32_t i = 0; i < resource->nof_symbols; i++) { for (uint32_t i = 0; i < resource->nof_symbols; i++) {
cf_t corr = srsran_vec_acc_cc(ce[i], nof_ref) / nof_ref; corr[i] = srsran_vec_acc_cc(ce[i], nof_ref) / nof_ref;
rsrp += __real__ corr * __real__ corr + __imag__ corr * __imag__ corr; rsrp += SRSRAN_CSQABS(corr[i]);
epre += srsran_vec_avg_power_cf(ce[i], nof_ref); epre += srsran_vec_avg_power_cf(ce[i], nof_ref);
ta_err += srsran_vec_estimate_frequency(ce[i], nof_ref); ta_err += srsran_vec_estimate_frequency(ce[i], nof_ref);
} }
@ -422,6 +440,24 @@ int srsran_dmrs_pucch_format2_estimate(const srsran_pucch_nr_t* q,
res->ta_us = 0.0f; res->ta_us = 0.0f;
} }
// Measure CFO
if (resource->nof_symbols > 1) {
float cfo_avg_hz = 0.0f;
for (uint32_t l = 0; l < resource->nof_symbols - 1; l++) {
uint32_t l0 = resource->start_symbol_idx + l;
uint32_t l1 = resource->start_symbol_idx + l + 1;
float time_diff = srsran_symbol_distance_s(l0, l1, q->carrier.scs);
float phase_diff = cargf(corr[l + 1] * conjf(corr[l]));
if (isnormal(time_diff)) {
cfo_avg_hz += phase_diff / (2.0f * M_PI * time_diff * (resource->nof_symbols - 1));
}
}
res->cfo_hz = cfo_avg_hz;
} else {
res->cfo_hz = NAN; // Not implemented
}
// Perform averaging // Perform averaging
// ... // ...

@ -817,7 +817,7 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q,
sync_err += srsran_vec_estimate_frequency(&q->pilot_estimates[nof_pilots_x_symbol * i], nof_pilots_x_symbol); sync_err += srsran_vec_estimate_frequency(&q->pilot_estimates[nof_pilots_x_symbol * i], nof_pilots_x_symbol);
} }
sync_err /= (float)nof_symbols; sync_err /= (float)nof_symbols;
chest_res->sync_error = sync_err / (dmrs_stride * SRSRAN_SUBC_SPACING_NR(q->carrier.scs)); float delay_us = sync_err / (dmrs_stride * SRSRAN_SUBC_SPACING_NR(q->carrier.scs));
#if DMRS_SCH_SYNC_PRECOMPENSATE #if DMRS_SCH_SYNC_PRECOMPENSATE
// Pre-compensate synchronization error // Pre-compensate synchronization error
@ -845,36 +845,52 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q,
epre /= nof_symbols; epre /= nof_symbols;
rsrp = SRSRAN_MIN(rsrp, epre - epre * 1e-7); rsrp = SRSRAN_MIN(rsrp, epre - epre * 1e-7);
chest_res->rsrp = rsrp;
chest_res->rsrp_dbm = srsran_convert_power_to_dB(chest_res->rsrp);
chest_res->noise_estimate = epre - rsrp;
chest_res->noise_estimate_dbm = srsran_convert_power_to_dB(chest_res->noise_estimate);
chest_res->snr_db = chest_res->rsrp_dbm - chest_res->noise_estimate_dbm;
// Measure CFO if more than one symbol is used // Measure CFO if more than one symbol is used
float cfo_avg = 0.0; float cfo_avg_hz = 0.0;
float cfo_hz_max = INFINITY;
for (uint32_t i = 0; i < nof_symbols - 1; i++) { for (uint32_t i = 0; i < nof_symbols - 1; i++) {
float time_diff = srsran_symbol_distance_s(symbols[i], symbols[i + 1], q->carrier.scs); float time_diff = srsran_symbol_distance_s(symbols[i], symbols[i + 1], q->carrier.scs);
float phase_diff = cargf(corr[i + 1] * conjf(corr[i])); float phase_diff = cargf(corr[i + 1] * conjf(corr[i]));
if (isnormal(time_diff)) { if (isnormal(time_diff)) {
cfo_avg += phase_diff / (2.0f * M_PI * time_diff * (nof_symbols - 1)); cfo_avg_hz += phase_diff / (2.0f * M_PI * time_diff * (nof_symbols - 1));
}
} // The maximum measured CFO depends on the symbol time difference
chest_res->cfo = cfo_avg; cfo_hz_max = SRSRAN_MIN(cfo_hz_max, 1 / time_diff);
}
}
// Store internal CSI
q->csi.rsrp = rsrp;
q->csi.rsrp_dB = srsran_convert_power_to_dB(rsrp);
q->csi.epre = epre;
q->csi.epre_dB = srsran_convert_power_to_dB(epre);
q->csi.n0 = epre - rsrp;
q->csi.n0_dB = srsran_convert_power_to_dB(q->csi.n0);
q->csi.snr_dB = q->csi.rsrp_dB - q->csi.n0_dB;
q->csi.cfo_hz = cfo_avg_hz;
q->csi.cfo_hz_max = cfo_hz_max;
q->csi.delay_us = delay_us;
// Write CSI in estimated channel result
chest_res->rsrp = q->csi.rsrp;
chest_res->rsrp_dbm = q->csi.rsrp_dB;
chest_res->noise_estimate = q->csi.n0;
chest_res->noise_estimate_dbm = q->csi.n0_dB;
chest_res->snr_db = q->csi.snr_dB;
chest_res->cfo = q->csi.cfo_hz;
chest_res->sync_error = q->csi.delay_us;
#if DMRS_SCH_CFO_PRECOMPENSATE #if DMRS_SCH_CFO_PRECOMPENSATE
// Pre-compensate CFO // Pre-compensate CFO
cf_t cfo_correction[SRSRAN_NSYMB_PER_SLOT_NR] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; cf_t cfo_correction[SRSRAN_NSYMB_PER_SLOT_NR] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
if (isnormal(cfo_avg)) { if (isnormal(cfo_avg_hz)) {
// Calculate phase of the first OFDM symbol (l = 0) // Calculate phase of the first OFDM symbol (l = 0)
float arg0 = cargf(corr[0]) - 2.0f * M_PI * srsran_symbol_distance_s(0, symbols[0], q->carrier.scs) * cfo_avg; float arg0 = cargf(corr[0]) - 2.0f * M_PI * srsran_symbol_distance_s(0, symbols[0], q->carrier.scs) * cfo_avg_hz;
// Calculate CFO corrections // Calculate CFO corrections
for (uint32_t l = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) { for (uint32_t l = 0; l < SRSRAN_NSYMB_PER_SLOT_NR; l++) {
float arg = arg0 + 2.0f * M_PI * cfo_avg * srsran_symbol_distance_s(0, l, q->carrier.scs); float arg = arg0 + 2.0f * M_PI * cfo_avg_hz * srsran_symbol_distance_s(0, l, q->carrier.scs);
cfo_correction[l] = cexpf(I * arg); cfo_correction[l] = cexpf(I * arg);
} }
@ -892,7 +908,7 @@ int srsran_dmrs_sch_estimate(srsran_dmrs_sch_t* q,
INFO("PDSCH-DMRS: RSRP=%+.2fdB EPRE=%+.2fdB CFO=%+.0fHz Sync=%.3fus", INFO("PDSCH-DMRS: RSRP=%+.2fdB EPRE=%+.2fdB CFO=%+.0fHz Sync=%.3fus",
chest_res->rsrp_dbm, chest_res->rsrp_dbm,
srsran_convert_power_to_dB(epre), srsran_convert_power_to_dB(epre),
cfo_avg, cfo_avg_hz,
chest_res->sync_error * 1e6); chest_res->sync_error * 1e6);
// Average over time, only if more than one DMRS symbol // Average over time, only if more than one DMRS symbol

@ -443,6 +443,22 @@ uint32_t srsran_csi_meas_info(const srsran_csi_trs_measurements_t* meas, char* s
meas->delay_us); meas->delay_us);
} }
uint32_t srsran_csi_meas_info_short(const srsran_csi_trs_measurements_t* meas, char* str, uint32_t str_len)
{
if (meas == NULL || str == NULL || str_len == 0) {
return 0;
}
return srsran_print_check(str,
str_len,
0,
"epre=%+.1f snr=%+.1f cfo=%+.1f delay=%+.1f ",
meas->epre_dB,
meas->snr_dB,
meas->cfo_hz,
meas->delay_us);
}
srsran_subcarrier_spacing_t srsran_subcarrier_spacing_from_str(const char* str) srsran_subcarrier_spacing_t srsran_subcarrier_spacing_from_str(const char* str)
{ {
if (str == NULL) { if (str == NULL) {
@ -674,3 +690,52 @@ int srsran_coreset_zero(uint32_t n_cell_id,
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
const char* srsran_ssb_pattern_to_str(srsran_ssb_patern_t pattern)
{
switch (pattern) {
case SRSRAN_SSB_PATTERN_A:
return "A";
case SRSRAN_SSB_PATTERN_B:
return "B";
case SRSRAN_SSB_PATTERN_C:
return "C";
case SRSRAN_SSB_PATTERN_D:
return "D";
case SRSRAN_SSB_PATTERN_E:
return "E";
case SRSRAN_SSB_PATTERN_INVALID:
default:
break;
}
return "Invalid";
}
srsran_ssb_patern_t srsran_ssb_pattern_fom_str(const char* str)
{
if (str == NULL) {
return SRSRAN_SSB_PATTERN_INVALID;
}
if (strcasecmp(str, "A") == 0) {
return SRSRAN_SSB_PATTERN_A;
}
if (strcasecmp(str, "B") == 0) {
return SRSRAN_SSB_PATTERN_B;
}
if (strcasecmp(str, "C") == 0) {
return SRSRAN_SSB_PATTERN_C;
}
if (strcasecmp(str, "D") == 0) {
return SRSRAN_SSB_PATTERN_D;
}
if (strcasecmp(str, "E") == 0) {
return SRSRAN_SSB_PATTERN_E;
}
return SRSRAN_SSB_PATTERN_INVALID;
}

@ -29,6 +29,11 @@
*/ */
#define GNB_UL_NR_FFT_WINDOW_OFFSET 0.5f #define GNB_UL_NR_FFT_WINDOW_OFFSET 0.5f
/**
* @brief Minimum PUSCH DMRS measured SINR default value
*/
#define GNB_UL_PUSCH_MIN_SNR_DEFAULT -10.0f
static int gnb_ul_alloc_prb(srsran_gnb_ul_t* q, uint32_t new_nof_prb) static int gnb_ul_alloc_prb(srsran_gnb_ul_t* q, uint32_t new_nof_prb)
{ {
if (q->max_prb < new_nof_prb) { if (q->max_prb < new_nof_prb) {
@ -92,6 +97,12 @@ int srsran_gnb_ul_init(srsran_gnb_ul_t* q, cf_t* input, const srsran_gnb_ul_args
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
// Set PUSCH minimum SNR, use default value if the given is NAN, INF or zero
q->pusch_min_snr_dB = GNB_UL_PUSCH_MIN_SNR_DEFAULT;
if (isnormal(args->pusch_min_snr_dB)) {
q->pusch_min_snr_dB = args->pusch_min_snr_dB;
}
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -144,7 +155,7 @@ int srsran_gnb_ul_set_carrier(srsran_gnb_ul_t* q, const srsran_carrier_nr_t* car
ofdm_cfg.rx_window_offset = GNB_UL_NR_FFT_WINDOW_OFFSET; ofdm_cfg.rx_window_offset = GNB_UL_NR_FFT_WINDOW_OFFSET;
ofdm_cfg.symbol_sz = srsran_min_symbol_sz_rb(carrier->nof_prb); ofdm_cfg.symbol_sz = srsran_min_symbol_sz_rb(carrier->nof_prb);
ofdm_cfg.keep_dc = true; ofdm_cfg.keep_dc = true;
ofdm_cfg.phase_compensation_hz = carrier->dl_center_frequency_hz; ofdm_cfg.phase_compensation_hz = carrier->ul_center_frequency_hz;
if (srsran_ofdm_rx_init_cfg(&q->fft, &ofdm_cfg) < SRSRAN_SUCCESS) { if (srsran_ofdm_rx_init_cfg(&q->fft, &ofdm_cfg) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -178,6 +189,15 @@ int srsran_gnb_ul_get_pusch(srsran_gnb_ul_t* q,
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
// Check PUSCH DMRS minimum SNR and abort PUSCH decoding if it is below the threshold
if (q->dmrs.csi.snr_dB < q->pusch_min_snr_dB) {
// Set PUSCH data as not decoded
data->tb[0].crc = false;
data->tb[0].avg_iter = NAN;
data->uci.valid = false;
return SRSRAN_SUCCESS;
}
if (srsran_pusch_nr_decode(&q->pusch, cfg, grant, &q->chest_pusch, q->sf_symbols, data) < SRSRAN_SUCCESS) { if (srsran_pusch_nr_decode(&q->pusch, cfg, grant, &q->chest_pusch, q->sf_symbols, data) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
@ -311,6 +331,7 @@ int srsran_gnb_ul_get_pucch(srsran_gnb_ul_t* q,
uint32_t srsran_gnb_ul_pucch_info(srsran_gnb_ul_t* q, uint32_t srsran_gnb_ul_pucch_info(srsran_gnb_ul_t* q,
const srsran_pucch_nr_resource_t* resource, const srsran_pucch_nr_resource_t* resource,
const srsran_uci_data_nr_t* uci_data, const srsran_uci_data_nr_t* uci_data,
const srsran_csi_trs_measurements_t* csi,
char* str, char* str,
uint32_t str_len) uint32_t str_len)
{ {
@ -320,10 +341,11 @@ uint32_t srsran_gnb_ul_pucch_info(srsran_gnb_ul_t* q,
uint32_t len = 0; uint32_t len = 0;
len += srsran_pucch_nr_info(resource, uci_data, str, str_len - len); len += srsran_pucch_nr_info(resource, uci_data, &str[len], str_len - len);
len += srsran_csi_meas_info_short(csi, &str[len], str_len - len);
len = srsran_print_check( len = srsran_print_check(str, str_len, len, "valid=%c ", uci_data->value.valid ? 'y' : 'n');
str, str_len, len, "snr=%+.1f valid=%c", q->chest_pucch.snr_db, uci_data->value.valid ? 'y' : 'n');
return len; return len;
} }
@ -342,7 +364,8 @@ uint32_t srsran_gnb_ul_pusch_info(srsran_gnb_ul_t* q,
len += srsran_pusch_nr_rx_info(&q->pusch, cfg, &cfg->grant, res, str, str_len - len); len += srsran_pusch_nr_rx_info(&q->pusch, cfg, &cfg->grant, res, str, str_len - len);
len = srsran_print_check(str, str_len, len, "snr=%+.1f", q->chest_pusch.snr_db); // Append channel estimator info
len += srsran_csi_meas_info_short(&q->dmrs.csi, &str[len], str_len - len);
return len; return len;
} }

@ -48,7 +48,6 @@ static bool csi_report_trigger(const srsran_csi_hl_report_cfg_t* cfg, uint32_t s
static void csi_wideband_cri_ri_pmi_cqi_quantify(const srsran_csi_hl_report_cfg_t* cfg, static void csi_wideband_cri_ri_pmi_cqi_quantify(const srsran_csi_hl_report_cfg_t* cfg,
const srsran_csi_channel_measurements_t* channel_meas, const srsran_csi_channel_measurements_t* channel_meas,
const srsran_csi_channel_measurements_t* interf_meas, const srsran_csi_channel_measurements_t* interf_meas,
srsran_csi_report_cfg_t* report_cfg,
srsran_csi_report_value_t* report_value) srsran_csi_report_value_t* report_value)
{ {
// Take SNR by default // Take SNR by default
@ -59,18 +58,6 @@ static void csi_wideband_cri_ri_pmi_cqi_quantify(const srsran_csi_hl_report_cfg_
wideband_sinr_db = channel_meas->wideband_rsrp_dBm - interf_meas->wideband_epre_dBm; wideband_sinr_db = channel_meas->wideband_rsrp_dBm - interf_meas->wideband_epre_dBm;
} }
// Fill report configuration
report_cfg->type = cfg->type;
report_cfg->quantity = SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI;
report_cfg->freq_cfg = SRSRAN_CSI_REPORT_FREQ_WIDEBAND;
report_cfg->nof_ports = channel_meas->nof_ports;
report_cfg->K_csi_rs = channel_meas->K_csi_rs;
// Save PUCCH resource only if periodic type
if (cfg->type == SRSRAN_CSI_REPORT_TYPE_PERIODIC) {
report_cfg->pucch_resource = cfg->periodic.resource;
}
// Fill quantified values // Fill quantified values
report_value->wideband_cri_ri_pmi_cqi.cqi = csi_snri_db_to_cqi(cfg->cqi_table, wideband_sinr_db); report_value->wideband_cri_ri_pmi_cqi.cqi = csi_snri_db_to_cqi(cfg->cqi_table, wideband_sinr_db);
report_value->wideband_cri_ri_pmi_cqi.ri = 0; report_value->wideband_cri_ri_pmi_cqi.ri = 0;
@ -199,48 +186,79 @@ int srsran_csi_new_nzp_csi_rs_measurement(
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
int srsran_csi_generate_reports(const srsran_csi_hl_cfg_t* cfg, int srsran_csi_reports_generate(const srsran_csi_hl_cfg_t* cfg,
uint32_t slot_idx, const srsran_slot_cfg_t* slot_cfg,
const srsran_csi_channel_measurements_t measurements[SRSRAN_CSI_MAX_NOF_RESOURCES], srsran_csi_report_cfg_t report_cfg[SRSRAN_CSI_MAX_NOF_REPORT])
srsran_csi_report_cfg_t report_cfg[SRSRAN_CSI_MAX_NOF_REPORT],
srsran_csi_report_value_t report_value[SRSRAN_CSI_MAX_NOF_REPORT])
{ {
uint32_t count = 0; uint32_t count = 0;
// Check inputs // Check inputs
if (cfg == NULL || measurements == NULL || report_cfg == NULL || report_value == NULL) { if (cfg == NULL || report_cfg == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS; return SRSRAN_ERROR_INVALID_INPUTS;
} }
// Make sure report configuration is initialised to zero
SRSRAN_MEM_ZERO(report_cfg, srsran_csi_report_cfg_t, SRSRAN_CSI_MAX_NOF_REPORT);
// Iterate every possible configured CSI report // Iterate every possible configured CSI report
for (uint32_t i = 0; i < SRSRAN_CSI_MAX_NOF_REPORT; i++) { for (uint32_t i = 0; i < SRSRAN_CSI_MAX_NOF_REPORT; i++) {
// Skip if report is not configured or triggered // Skip if report is not configured or triggered
if (!csi_report_trigger(&cfg->reports[i], slot_idx)) { if (!csi_report_trigger(&cfg->reports[i], slot_cfg->idx)) {
continue; continue;
} }
// Configure report
report_cfg[count].cfg = cfg->reports[i];
report_cfg[count].nof_ports = 1;
report_cfg[count].K_csi_rs = 1;
report_cfg[count].has_part2 = false;
count++;
}
return (int)count;
}
int srsran_csi_reports_quantify(const srsran_csi_report_cfg_t reports[SRSRAN_CSI_MAX_NOF_REPORT],
const srsran_csi_channel_measurements_t measurements[SRSRAN_CSI_MAX_NOF_RESOURCES],
srsran_csi_report_value_t report_value[SRSRAN_CSI_MAX_NOF_REPORT])
{
uint32_t count = 0;
// Check inputs
if (reports == NULL || measurements == NULL || report_value == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Iterate every possible configured CSI report
for (uint32_t i = 0; i < SRSRAN_CSI_MAX_NOF_REPORT; i++) {
// If the report is the last one, break
if (reports->cfg.type == SRSRAN_CSI_REPORT_TYPE_NONE) {
break;
}
// Select channel measurement // Select channel measurement
if (cfg->reports->channel_meas_id >= SRSRAN_CSI_MAX_NOF_RESOURCES) { uint32_t channel_meas_id = reports[i].cfg.channel_meas_id;
ERROR("Channel measurement ID (%d) is out of range", cfg->reports->channel_meas_id); if (channel_meas_id >= SRSRAN_CSI_MAX_NOF_RESOURCES) {
ERROR("Channel measurement ID (%d) is out of range", channel_meas_id);
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
const srsran_csi_channel_measurements_t* channel_meas = &measurements[cfg->reports->channel_meas_id]; const srsran_csi_channel_measurements_t* channel_meas = &measurements[channel_meas_id];
// Select interference measurement // Select interference measurement
const srsran_csi_channel_measurements_t* interf_meas = NULL; const srsran_csi_channel_measurements_t* interf_meas = NULL;
if (cfg->reports->interf_meas_present) { if (reports[i].cfg.interf_meas_present) {
if (cfg->reports->interf_meas_id >= SRSRAN_CSI_MAX_NOF_RESOURCES) { uint32_t interf_meas_id = reports[i].cfg.interf_meas_id;
ERROR("Interference measurement ID (%d) is out of range", cfg->reports->interf_meas_id); if (interf_meas_id >= SRSRAN_CSI_MAX_NOF_RESOURCES) {
ERROR("Interference measurement ID (%d) is out of range", interf_meas_id);
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
interf_meas = &measurements[cfg->reports->interf_meas_id]; interf_meas = &measurements[interf_meas_id];
} }
// Quantify measurements according to frequency and quantity configuration // Quantify measurements according to frequency and quantity configuration
if (cfg->reports->freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND && if (reports[i].cfg.freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND &&
cfg->reports->quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { reports[i].cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
csi_wideband_cri_ri_pmi_cqi_quantify( csi_wideband_cri_ri_pmi_cqi_quantify(&reports[i].cfg, channel_meas, interf_meas, &report_value[count]);
&cfg->reports[i], channel_meas, interf_meas, &report_cfg[count], &report_value[count]);
count++; count++;
} else { } else {
; // Ignore other types ; // Ignore other types
@ -262,9 +280,9 @@ int srsran_csi_part1_nof_bits(const srsran_csi_report_cfg_t* report_list, uint32
// Iterate all report configurations // Iterate all report configurations
for (uint32_t i = 0; i < nof_reports; i++) { for (uint32_t i = 0; i < nof_reports; i++) {
const srsran_csi_report_cfg_t* report = &report_list[i]; const srsran_csi_report_cfg_t* report = &report_list[i];
if (report->quantity && report->quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { if (report->cfg.quantity && report->cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
count += csi_wideband_cri_ri_pmi_cqi_nof_bits(report); count += csi_wideband_cri_ri_pmi_cqi_nof_bits(report);
} else if (report->quantity == SRSRAN_CSI_REPORT_QUANTITY_NONE) { } else if (report->cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_NONE) {
count += csi_none_nof_bits(report); count += csi_none_nof_bits(report);
} }
} }
@ -317,15 +335,15 @@ int srsran_csi_part1_pack(const srsran_csi_report_cfg_t* report_cfg,
} }
for (uint32_t i = 0; i < nof_reports && count < max_o_csi1; i++) { for (uint32_t i = 0; i < nof_reports && count < max_o_csi1; i++) {
if (report_cfg[i].freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND && if (report_cfg[i].cfg.freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND &&
report_cfg[i].quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { report_cfg[i].cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
count += csi_wideband_cri_ri_pmi_cqi_pack(&report_cfg[i], &report_value[i], &o_csi1[count]); count += csi_wideband_cri_ri_pmi_cqi_pack(&report_cfg[i], &report_value[i], &o_csi1[count]);
} else if (report_cfg[i].quantity == SRSRAN_CSI_REPORT_QUANTITY_NONE) { } else if (report_cfg[i].cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_NONE) {
count += csi_none_pack(&report_cfg[i], &report_value[i], &o_csi1[count]); count += csi_none_pack(&report_cfg[i], &report_value[i], &o_csi1[count]);
} else { } else {
ERROR("CSI frequency (%d) and quantity (%d) combination is not implemented", ERROR("CSI frequency (%d) and quantity (%d) combination is not implemented",
report_cfg[i].freq_cfg, report_cfg[i].cfg.freq_cfg,
report_cfg[i].quantity); report_cfg[i].cfg.quantity);
} }
} }
@ -351,15 +369,15 @@ int srsran_csi_part1_unpack(const srsran_csi_report_cfg_t* report_cfg,
} }
for (uint32_t i = 0; i < nof_reports && count < max_o_csi1; i++) { for (uint32_t i = 0; i < nof_reports && count < max_o_csi1; i++) {
if (report_cfg[i].freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND && if (report_cfg[i].cfg.freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND &&
report_cfg[i].quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { report_cfg[i].cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
count += csi_wideband_cri_ri_pmi_cqi_unpack(&report_cfg[i], &o_csi1[count], &report_value[i]); count += csi_wideband_cri_ri_pmi_cqi_unpack(&report_cfg[i], &o_csi1[count], &report_value[i]);
} else if (report_cfg[i].quantity == SRSRAN_CSI_REPORT_QUANTITY_NONE) { } else if (report_cfg[i].cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_NONE) {
count += csi_none_unpack(&report_cfg[i], &o_csi1[count], &report_value[i]); count += csi_none_unpack(&report_cfg[i], &o_csi1[count], &report_value[i]);
} else { } else {
ERROR("CSI frequency (%d) and quantity (%d) combination is not implemented", ERROR("CSI frequency (%d) and quantity (%d) combination is not implemented",
report_cfg[i].freq_cfg, report_cfg[i].cfg.freq_cfg,
report_cfg[i].quantity); report_cfg[i].cfg.quantity);
} }
} }
@ -374,10 +392,10 @@ uint32_t srsran_csi_str(const srsran_csi_report_cfg_t* report_cfg,
{ {
uint32_t len = 0; uint32_t len = 0;
for (uint32_t i = 0; i < nof_reports; i++) { for (uint32_t i = 0; i < nof_reports; i++) {
if (report_cfg[i].freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND && if (report_cfg[i].cfg.freq_cfg == SRSRAN_CSI_REPORT_FREQ_WIDEBAND &&
report_cfg[i].quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { report_cfg[i].cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) {
len = srsran_print_check(str, str_len, len, "cqi=%d ", report_value[i].wideband_cri_ri_pmi_cqi.cqi); len = srsran_print_check(str, str_len, len, "cqi=%d ", report_value[i].wideband_cri_ri_pmi_cqi.cqi);
} else if (report_cfg[i].quantity == SRSRAN_CSI_REPORT_QUANTITY_NONE) { } else if (report_cfg[i].cfg.quantity == SRSRAN_CSI_REPORT_QUANTITY_NONE) {
char tmp[20] = {}; char tmp[20] = {};
srsran_vec_sprint_bin(tmp, sizeof(tmp), report_value[i].none, report_cfg->K_csi_rs); srsran_vec_sprint_bin(tmp, sizeof(tmp), report_value[i].none, report_cfg->K_csi_rs);
len = srsran_print_check(str, str_len, len, "csi=%s ", tmp); len = srsran_print_check(str, str_len, len, "csi=%s ", tmp);

@ -2081,10 +2081,11 @@ uint32_t srsran_dci_ctx_to_str(const srsran_dci_ctx_t* ctx, char* str, uint32_t
len = srsran_print_check(str, len = srsran_print_check(str,
str_len, str_len,
len, len,
"%s-rnti=%04x dci=%s ", "%s-rnti=%04x dci=%s ss=%s ",
srsran_rnti_type_str_short(ctx->rnti_type), srsran_rnti_type_str_short(ctx->rnti_type),
ctx->rnti, ctx->rnti,
srsran_dci_format_nr_string(ctx->format)); srsran_dci_format_nr_string(ctx->format),
srsran_ss_type_str(ctx->ss_type));
if (ctx->format != srsran_dci_format_nr_rar) { if (ctx->format != srsran_dci_format_nr_rar) {
len = srsran_print_check(str, str_len, len, "L=%d cce=%d ", ctx->location.L, ctx->location.ncce); len = srsran_print_check(str, str_len, len, "L=%d cce=%d ", ctx->location.L, ctx->location.ncce);

@ -419,9 +419,11 @@ static void pbch_nr_scramble_tx(const srsran_pbch_nr_cfg_t* cfg,
uint32_t M_bit = PBCH_NR_E; uint32_t M_bit = PBCH_NR_E;
// Select value v // Select value v
uint32_t v = (ssb_idx & 0x7U); // for L max = 8 or L max = 64 , & is the three least significant bits of the SS/PBCH block index
uint32_t v = (ssb_idx & 0b111U);
if (cfg->Lmax == 4) { if (cfg->Lmax == 4) {
v = ssb_idx & 0x3U; // for L max = 4 , & is the two least significant bits of the SS/PBCH block index
v = ssb_idx & 0b11U;
} }
// Advance sequence // Advance sequence
@ -444,8 +446,10 @@ static void pbch_nr_scramble_rx(const srsran_pbch_nr_cfg_t* cfg,
uint32_t M_bit = PBCH_NR_E; uint32_t M_bit = PBCH_NR_E;
// Select value v // Select value v
// for L max = 8 or L max = 64 , & is the three least significant bits of the SS/PBCH block index
uint32_t v = (ssb_idx & 0b111U); uint32_t v = (ssb_idx & 0b111U);
if (cfg->Lmax == 4) { if (cfg->Lmax == 4) {
// for L max = 4 , & is the two least significant bits of the SS/PBCH block index
v = ssb_idx & 0b11U; v = ssb_idx & 0b11U;
} }

@ -577,6 +577,10 @@ static uint32_t pdsch_nr_grant_info(const srsran_pdsch_nr_t* q,
} }
} }
// Append RNTI type and id
len =
srsran_print_check(str, str_len, len, "%s-rnti=0x%x ", srsran_rnti_type_str_short(grant->rnti_type), grant->rnti);
// Append time-domain resource mapping // Append time-domain resource mapping
len = srsran_print_check(str, len = srsran_print_check(str,
str_len, str_len,

@ -624,7 +624,9 @@ int srsran_prach_set_cell_(srsran_prach_t* p,
int ret = SRSRAN_ERROR; int ret = SRSRAN_ERROR;
if (p != NULL && N_ifft_ul < 2049 && cfg->config_idx < 64 && cfg->root_seq_idx < MAX_ROOTS) { if (p != NULL && N_ifft_ul < 2049 && cfg->config_idx < 64 && cfg->root_seq_idx < MAX_ROOTS) {
if (N_ifft_ul > p->max_N_ifft_ul) { if (N_ifft_ul > p->max_N_ifft_ul) {
ERROR("PRACH: Error in set_cell(): N_ifft_ul must be lower or equal max_N_ifft_ul in init()"); ERROR("PRACH: Error in set_cell(): N_ifft_ul (%d) must be lower or equal max_N_ifft_ul (%d) in init()",
N_ifft_ul,
p->max_N_ifft_ul);
return -1; return -1;
} }
@ -752,7 +754,7 @@ int srsran_prach_gen(srsran_prach_t* p, uint32_t seq_index, uint32_t freq_offset
uint32_t N_rb_ul = srsran_nof_prb(p->N_ifft_ul); uint32_t N_rb_ul = srsran_nof_prb(p->N_ifft_ul);
uint32_t k_0 = freq_offset * N_RB_SC - N_rb_ul * N_RB_SC / 2 + p->N_ifft_ul / 2; uint32_t k_0 = freq_offset * N_RB_SC - N_rb_ul * N_RB_SC / 2 + p->N_ifft_ul / 2;
uint32_t K = DELTA_F / DELTA_F_RA; uint32_t K = DELTA_F / DELTA_F_RA;
uint32_t begin = PHI + (K * k_0) + (p->is_nr ? 1 : (K / 2)); uint32_t begin = PHI + (K * k_0) + (p->is_nr ? 0 : (K / 2));
if (6 + freq_offset > N_rb_ul) { if (6 + freq_offset > N_rb_ul) {
ERROR("Error no space for PRACH: frequency offset=%d, N_rb_ul=%d", freq_offset, N_rb_ul); ERROR("Error no space for PRACH: frequency offset=%d, N_rb_ul=%d", freq_offset, N_rb_ul);
@ -762,11 +764,16 @@ int srsran_prach_gen(srsran_prach_t* p, uint32_t seq_index, uint32_t freq_offset
DEBUG( DEBUG(
"N_zc: %d, N_cp: %d, N_seq: %d, N_ifft_prach=%d begin: %d", p->N_zc, p->N_cp, p->N_seq, p->N_ifft_prach, begin); "N_zc: %d, N_cp: %d, N_seq: %d, N_ifft_prach=%d begin: %d", p->N_zc, p->N_cp, p->N_seq, p->N_ifft_prach, begin);
// Fill bottom guard frequency domain with zeros
srsran_vec_cf_zero(p->ifft_in, begin);
// Map dft-precoded sequence to ifft bins // Map dft-precoded sequence to ifft bins
memset(p->ifft_in, 0, begin * sizeof(cf_t)); srsran_vec_cf_copy(&p->ifft_in[begin], get_precoded_dft(p, seq_index), p->N_zc);
memcpy(&p->ifft_in[begin], get_precoded_dft(p, seq_index), p->N_zc * sizeof(cf_t));
memset(&p->ifft_in[begin + p->N_zc], 0, (p->N_ifft_prach - begin - p->N_zc) * sizeof(cf_t)); // Fill top guard frequency domain with zeros
srsran_vec_cf_zero(&p->ifft_in[begin + p->N_zc], p->N_ifft_prach - begin - p->N_zc);
// Generate frequency domain signal
srsran_dft_run(&p->ifft, p->ifft_in, p->ifft_out); srsran_dft_run(&p->ifft, p->ifft_in, p->ifft_out);
// Copy CP into buffer // Copy CP into buffer
@ -986,7 +993,7 @@ int srsran_prach_detect_offset(srsran_prach_t* p,
uint32_t N_rb_ul = srsran_nof_prb(p->N_ifft_ul); uint32_t N_rb_ul = srsran_nof_prb(p->N_ifft_ul);
uint32_t k_0 = freq_offset * N_RB_SC - N_rb_ul * N_RB_SC / 2 + p->N_ifft_ul / 2; uint32_t k_0 = freq_offset * N_RB_SC - N_rb_ul * N_RB_SC / 2 + p->N_ifft_ul / 2;
uint32_t K = DELTA_F / DELTA_F_RA; uint32_t K = DELTA_F / DELTA_F_RA;
uint32_t begin = PHI + (K * k_0) + (K / 2); uint32_t begin = PHI + (K * k_0) + (p->is_nr ? 0 : (K / 2));
memcpy(p->prach_bins, &p->signal_fft[begin], p->N_zc * sizeof(cf_t)); memcpy(p->prach_bins, &p->signal_fft[begin], p->N_zc * sizeof(cf_t));
int loops = (p->successive_cancellation) ? SUCCESSIVE_CANCELLATION_ITS : 1; int loops = (p->successive_cancellation) ? SUCCESSIVE_CANCELLATION_ITS : 1;

@ -481,8 +481,9 @@ int srsran_pucch_nr_format1_decode(srsran_pucch_nr_t* q,
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
// Received symbol d // Accumulates received symbol d and average power
cf_t d = 0; cf_t d = 0;
float pwr_acc = 0.0f;
// Get group sequence // Get group sequence
uint32_t u = 0; uint32_t u = 0;
@ -526,22 +527,33 @@ int srsran_pucch_nr_format1_decode(srsran_pucch_nr_t* q,
srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE); srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE);
// Compute d = sum(x * conj(w(i) * r_uv(n))) = sum(w(i) * d' * r_uv(n) * conj(w(i) * r_uv(n))) = d' // Compute d = sum(x * conj(w(i) * r_uv(n))) = sum(w(i) * d' * r_uv(n) * conj(w(i) * r_uv(n))) = d'
d += srsran_vec_dot_prod_conj_ccc(x, z, SRSRAN_NRE); d += srsran_vec_dot_prod_conj_ccc(x, z, SRSRAN_NRE) / SRSRAN_NRE;
// Compute and accumulate average symbol power
pwr_acc += srsran_vec_avg_power_cf(x, SRSRAN_NRE);
} }
// Demodulate d // Demodulate d
float llr[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS]; float llr[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS];
srsran_demod_soft_demodulate((nof_bits == 1) ? SRSRAN_MOD_BPSK : SRSRAN_MOD_QPSK, &d, llr, 1); srsran_demod_soft_demodulate((nof_bits == 1) ? SRSRAN_MOD_BPSK : SRSRAN_MOD_QPSK, &d, llr, 1);
// Hard decision // Hard decision based on the LLRs sign
float corr = 0.0f;
for (uint32_t i = 0; i < nof_bits; i++) { for (uint32_t i = 0; i < nof_bits; i++) {
b[i] = llr[i] > 0.0f ? 1 : 0; b[i] = llr[i] > 0.0f ? 1 : 0;
corr += fabsf(llr[i]);
} }
if (norm_corr != NULL && nof_bits > 0) { // Calculate normalised correlation, it uses the absolute value of d and accumulated average power
*norm_corr = corr / nof_bits; if (norm_corr != NULL) {
// Get the number of payload symbols. As the one of every 2 symbols carry DMRS, the payload symbols is half of the
// total symbols rounding down
float nsymb = (float)SRSRAN_FLOOR(resource->nof_symbols, 2);
// Avoid zero, INF or NAN division, set correlation to 0 in this case
if (isnormal(pwr_acc) && isnormal(nsymb)) {
*norm_corr = cabsf(d) / sqrtf(pwr_acc * nsymb);
} else {
*norm_corr = 0.0f;
}
} }
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;

@ -1019,6 +1019,10 @@ static uint32_t pusch_nr_grant_info(const srsran_pusch_nr_t* q,
} }
} }
// Append RNTI type and id
len =
srsran_print_check(str, str_len, len, "%s-rnti=0x%x ", srsran_rnti_type_str_short(grant->rnti_type), grant->rnti);
// Append time-domain resource mapping // Append time-domain resource mapping
len = srsran_print_check(str, len = srsran_print_check(str,
str_len, str_len,

@ -21,6 +21,7 @@
#include "srsran/phy/phch/ra_nr.h" #include "srsran/phy/phch/ra_nr.h"
#include "srsran/phy/ch_estimation/csi_rs.h" #include "srsran/phy/ch_estimation/csi_rs.h"
#include "srsran/phy/fec/cbsegm.h"
#include "srsran/phy/phch/csi.h" #include "srsran/phy/phch/csi.h"
#include "srsran/phy/phch/pdsch_nr.h" #include "srsran/phy/phch/pdsch_nr.h"
#include "srsran/phy/phch/ra_dl_nr.h" #include "srsran/phy/phch/ra_dl_nr.h"
@ -459,6 +460,28 @@ static int ra_nr_assert_csi_rs_dmrs_collision(const srsran_sch_cfg_nr_t* pdsch_c
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
uint32_t ra_nr_nof_crc_bits(uint32_t tbs, double R)
{
srsran_cbsegm_t cbsegm = {};
srsran_basegraph_t bg = srsran_sch_nr_select_basegraph(tbs, R);
if (bg == BG1) {
if (srsran_cbsegm_ldpc_bg1(&cbsegm, tbs) != SRSRAN_SUCCESS) {
// This should never fail
ERROR("Error: calculating LDPC BG1 code block segmentation for tbs=%d", tbs);
return 0;
}
} else {
if (srsran_cbsegm_ldpc_bg2(&cbsegm, tbs) != SRSRAN_SUCCESS) {
// This should never fail
ERROR("Error: calculating LDPC BG1 code block segmentation for tbs=%d", tbs);
return 0;
}
}
return cbsegm.C * cbsegm.L_cb + cbsegm.L_tb;
}
int srsran_ra_nr_fill_tb(const srsran_sch_cfg_nr_t* pdsch_cfg, int srsran_ra_nr_fill_tb(const srsran_sch_cfg_nr_t* pdsch_cfg,
const srsran_sch_grant_nr_t* grant, const srsran_sch_grant_nr_t* grant,
uint32_t mcs_idx, uint32_t mcs_idx,
@ -533,7 +556,7 @@ int srsran_ra_nr_fill_tb(const srsran_sch_cfg_nr_t* pdsch_cfg,
// Calculate actual rate // Calculate actual rate
tb->R_prime = 0.0; tb->R_prime = 0.0;
if (tb->nof_re != 0) { if (tb->nof_re != 0) {
tb->R_prime = (double)tb->tbs / (double)tb->nof_bits; tb->R_prime = (double)(tb->tbs + ra_nr_nof_crc_bits(tb->tbs, tb->R)) / (double)tb->nof_bits;
} }
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
@ -1051,7 +1074,10 @@ int srsran_ra_ul_set_grant_uci_nr(const srsran_carrier_nr_t* carrier,
pusch_cfg->grant.tb[i].nof_re * srsran_mod_bits_x_symbol(pusch_cfg->grant.tb[i].mod) - Gack - Gcsi1 - Gcsi2; pusch_cfg->grant.tb[i].nof_re * srsran_mod_bits_x_symbol(pusch_cfg->grant.tb[i].mod) - Gack - Gcsi1 - Gcsi2;
if (pusch_cfg->grant.tb[i].nof_bits > 0) { if (pusch_cfg->grant.tb[i].nof_bits > 0) {
pusch_cfg->grant.tb[i].R_prime = (double)pusch_cfg->grant.tb[i].tbs / (double)pusch_cfg->grant.tb[i].nof_bits; pusch_cfg->grant.tb[i].R_prime =
(double)(pusch_cfg->grant.tb[i].tbs +
ra_nr_nof_crc_bits(pusch_cfg->grant.tb[i].tbs, pusch_cfg->grant.tb[i].R)) /
(double)pusch_cfg->grant.tb[i].nof_bits;
} else { } else {
pusch_cfg->grant.tb[i].R_prime = NAN; pusch_cfg->grant.tb[i].R_prime = NAN;
} }

@ -623,8 +623,8 @@ int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg,
// - Irrelevant SR opportunities // - Irrelevant SR opportunities
// - No HARQ-ACK // - No HARQ-ACK
// - Single periodic CSI report // - Single periodic CSI report
if (uci_cfg->ack.count == 0 && uci_cfg->nof_csi == 1 && uci_cfg->csi[0].type == SRSRAN_CSI_REPORT_TYPE_PERIODIC) { if (uci_cfg->ack.count == 0 && uci_cfg->nof_csi == 1 && uci_cfg->csi[0].cfg.type == SRSRAN_CSI_REPORT_TYPE_PERIODIC) {
*resource = uci_cfg->csi[0].pucch_resource; *resource = uci_cfg->csi[0].cfg.periodic.resource;
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }

@ -96,7 +96,7 @@ static int sch_nr_Nref(uint32_t N_rb, srsran_mcs_table_t mcs_table, uint32_t max
uint32_t N_re_lbrm = SRSRAN_MAX_NRE_NR * sch_nr_n_prb_lbrm(N_rb); uint32_t N_re_lbrm = SRSRAN_MAX_NRE_NR * sch_nr_n_prb_lbrm(N_rb);
double TCR_lbrm = 948.0 / 1024.0; double TCR_lbrm = 948.0 / 1024.0;
uint32_t Qm_lbrm = (mcs_table == srsran_mcs_table_256qam) ? 8 : 6; uint32_t Qm_lbrm = (mcs_table == srsran_mcs_table_256qam) ? 8 : 6;
uint32_t TBS_LRBM = srsran_ra_nr_tbs(N_re_lbrm, 1.0, TCR_lbrm, Qm_lbrm, max_mimo_layers); uint32_t TBS_LRBM = srsran_ra_nr_tbs(N_re_lbrm, 1.0, TCR_lbrm, Qm_lbrm, SRSRAN_MIN(4, max_mimo_layers));
double R = 2.0 / 3.0; double R = 2.0 / 3.0;
srsran_basegraph_t bg = srsran_sch_nr_select_basegraph(TBS_LRBM, R); srsran_basegraph_t bg = srsran_sch_nr_select_basegraph(TBS_LRBM, R);
@ -150,11 +150,15 @@ int srsran_sch_nr_fill_tb_info(const srsran_carrier_nr_t* carrier,
cfg->Nl = tb->N_L; cfg->Nl = tb->N_L;
// Calculate Nref // Calculate Nref
int Nref = sch_nr_Nref(carrier->nof_prb, sch_cfg->mcs_table, carrier->max_mimo_layers); if (sch_cfg->limited_buffer_rm) {
int Nref = sch_nr_Nref(carrier->nof_prb, sch_cfg->mcs_table, 4);
if (Nref < SRSRAN_SUCCESS) { if (Nref < SRSRAN_SUCCESS) {
ERROR("Error computing N_ref"); ERROR("Error computing N_ref");
} }
cfg->Nref = (uint32_t)Nref; cfg->Nref = (uint32_t)Nref;
} else {
cfg->Nref = SRSRAN_LDPC_MAX_LEN_ENCODED_CB;
}
// Calculate number of code blocks after applying CBGTI... not implemented, activate all CB // Calculate number of code blocks after applying CBGTI... not implemented, activate all CB
for (uint32_t r = 0; r < cbsegm.C; r++) { for (uint32_t r = 0; r < cbsegm.C; r++) {

@ -585,6 +585,8 @@ add_lte_test(prach_zc0 prach_test -z 0)
add_lte_test(prach_zc2 prach_test -z 2) add_lte_test(prach_zc2 prach_test -z 2)
add_lte_test(prach_zc3 prach_test -z 3) add_lte_test(prach_zc3 prach_test -z 3)
add_nr_test(prach_nr prach_test -n 50 -f 0 -r 0 -z 0 -N 1)
add_executable(prach_test_multi prach_test_multi.c) add_executable(prach_test_multi prach_test_multi.c)
target_link_libraries(prach_test_multi srsran_phy) target_link_libraries(prach_test_multi srsran_phy)

@ -32,6 +32,7 @@
#define MAX_LEN 70176 #define MAX_LEN 70176
static bool is_nr = false;
static uint32_t nof_prb = 50; static uint32_t nof_prb = 50;
static uint32_t config_idx = 3; static uint32_t config_idx = 3;
static uint32_t root_seq_idx = 0; static uint32_t root_seq_idx = 0;
@ -45,12 +46,13 @@ static void usage(char* prog)
printf("\t-f Preamble format [Default 0]\n"); printf("\t-f Preamble format [Default 0]\n");
printf("\t-r Root sequence index [Default 0]\n"); printf("\t-r Root sequence index [Default 0]\n");
printf("\t-z Zero correlation zone config [Default 1]\n"); printf("\t-z Zero correlation zone config [Default 1]\n");
printf("\t-N Toggle LTE/NR operation, zero for LTE, non-zero for NR [Default %s]\n", is_nr ? "NR" : "LTE");
} }
static void parse_args(int argc, char** argv) static void parse_args(int argc, char** argv)
{ {
int opt; int opt;
while ((opt = getopt(argc, argv, "nfrz")) != -1) { while ((opt = getopt(argc, argv, "nfrzN")) != -1) {
switch (opt) { switch (opt) {
case 'n': case 'n':
nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
@ -64,6 +66,9 @@ static void parse_args(int argc, char** argv)
case 'z': case 'z':
zero_corr_zone = (uint32_t)strtol(argv[optind], NULL, 10); zero_corr_zone = (uint32_t)strtol(argv[optind], NULL, 10);
break; break;
case 'N':
is_nr = (uint32_t)strtol(argv[optind], NULL, 10) > 0;
break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
@ -83,6 +88,7 @@ int main(int argc, char** argv)
srsran_prach_cfg_t prach_cfg; srsran_prach_cfg_t prach_cfg;
ZERO_OBJECT(prach_cfg); ZERO_OBJECT(prach_cfg);
prach_cfg.is_nr = is_nr;
prach_cfg.config_idx = config_idx; prach_cfg.config_idx = config_idx;
prach_cfg.hs_flag = high_speed_flag; prach_cfg.hs_flag = high_speed_flag;
prach_cfg.freq_offset = 0; prach_cfg.freq_offset = 0;

@ -234,7 +234,7 @@ int main(int argc, char** argv)
uint8_t csi_report_tx[SRSRAN_UCI_NR_MAX_CSI1_BITS] = {}; uint8_t csi_report_tx[SRSRAN_UCI_NR_MAX_CSI1_BITS] = {};
uint8_t csi_report_rx[SRSRAN_UCI_NR_MAX_CSI1_BITS] = {}; uint8_t csi_report_rx[SRSRAN_UCI_NR_MAX_CSI1_BITS] = {};
if (nof_csi_bits > 0) { if (nof_csi_bits > 0) {
pusch_cfg.uci.csi[0].quantity = SRSRAN_CSI_REPORT_QUANTITY_NONE; pusch_cfg.uci.csi[0].cfg.quantity = SRSRAN_CSI_REPORT_QUANTITY_NONE;
pusch_cfg.uci.csi[0].K_csi_rs = nof_csi_bits; pusch_cfg.uci.csi[0].K_csi_rs = nof_csi_bits;
pusch_cfg.uci.nof_csi = 1; pusch_cfg.uci.nof_csi = 1;
data_tx.uci.csi[0].none = csi_report_tx; data_tx.uci.csi[0].none = csi_report_tx;

@ -308,8 +308,7 @@ static int uci_nr_A(const srsran_uci_cfg_nr_t* cfg)
} }
// 6.3.1.1.3 HARQ-ACK/SR and CSI // 6.3.1.1.3 HARQ-ACK/SR and CSI
ERROR("HARQ-ACK/SR and CSI encoding are not implemented"); return cfg->ack.count + cfg->o_sr + o_csi;
return SRSRAN_ERROR;
} }
static int uci_nr_pack_pucch(const srsran_uci_cfg_nr_t* cfg, const srsran_uci_value_nr_t* value, uint8_t* sequence) static int uci_nr_pack_pucch(const srsran_uci_cfg_nr_t* cfg, const srsran_uci_value_nr_t* value, uint8_t* sequence)
@ -341,8 +340,7 @@ static int uci_nr_unpack_pucch(const srsran_uci_cfg_nr_t* cfg, uint8_t* sequence
// 6.3.1.1.2 CSI only // 6.3.1.1.2 CSI only
if (cfg->ack.count == 0 && cfg->o_sr == 0) { if (cfg->ack.count == 0 && cfg->o_sr == 0) {
ERROR("CSI only are not implemented"); return srsran_csi_part1_unpack(cfg->csi, cfg->nof_csi, sequence, SRSRAN_UCI_NR_MAX_NOF_BITS, value->csi);
return SRSRAN_ERROR;
} }
// 6.3.1.1.3 HARQ-ACK/SR and CSI // 6.3.1.1.3 HARQ-ACK/SR and CSI
@ -644,9 +642,11 @@ static int uci_nr_decode_3_11_bit(srsran_uci_nr_t* q,
// Compute average LLR power // Compute average LLR power
float pwr = srsran_vec_avg_power_bf(llr, E); float pwr = srsran_vec_avg_power_bf(llr, E);
// If the power measurement is invalid (zero, NAN, INF) then consider it cannot be decoded
if (!isnormal(pwr)) { if (!isnormal(pwr)) {
ERROR("Received all zeros"); *decoded_ok = false;
return SRSRAN_ERROR; return SRSRAN_SUCCESS;
} }
// Decode // Decode

@ -190,7 +190,9 @@ int srsran_rf_close(srsran_rf_t* rf)
} }
pthread_mutex_unlock(&rf->mutex); pthread_mutex_unlock(&rf->mutex);
pthread_cond_signal(&rf->cond); pthread_cond_signal(&rf->cond);
if (rf->thread_gain) {
pthread_join(rf->thread_gain, NULL); pthread_join(rf->thread_gain, NULL);
}
return ((rf_dev_t*)rf->dev)->srsran_rf_close(rf->handler); return ((rf_dev_t*)rf->dev)->srsran_rf_close(rf->handler);
} }

@ -19,6 +19,7 @@
* *
*/ */
#include <atomic>
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
#include <string> #include <string>
@ -164,7 +165,7 @@ struct rf_uhd_handler_t {
#if HAVE_ASYNC_THREAD #if HAVE_ASYNC_THREAD
// Asynchronous transmission message thread // Asynchronous transmission message thread
bool async_thread_running = false; std::atomic<bool> async_thread_running{false};
std::thread async_thread; std::thread async_thread;
std::mutex async_mutex; std::mutex async_mutex;
std::condition_variable async_cvar; std::condition_variable async_cvar;
@ -235,10 +236,13 @@ static void log_late(rf_uhd_handler_t* h, bool is_rx)
#if HAVE_ASYNC_THREAD #if HAVE_ASYNC_THREAD
static void log_underflow(rf_uhd_handler_t* h) static void log_underflow(rf_uhd_handler_t* h)
{ {
{
std::lock_guard<std::mutex> tx_lock(h->tx_mutex);
// Flag underflow // Flag underflow
if (h->tx_state == RF_UHD_IMP_TX_STATE_BURST) { if (h->tx_state == RF_UHD_IMP_TX_STATE_BURST) {
h->tx_state = RF_UHD_IMP_TX_STATE_END_OF_BURST; h->tx_state = RF_UHD_IMP_TX_STATE_END_OF_BURST;
} }
}
if (h->uhd_error_handler != nullptr) { if (h->uhd_error_handler != nullptr) {
srsran_rf_error_t error; srsran_rf_error_t error;
bzero(&error, sizeof(srsran_rf_error_t)); bzero(&error, sizeof(srsran_rf_error_t));
@ -298,6 +302,7 @@ static void* async_thread(void* h)
} }
} else if (event_code == uhd::async_metadata_t::EVENT_CODE_BURST_ACK) { } else if (event_code == uhd::async_metadata_t::EVENT_CODE_BURST_ACK) {
// Makes sure next block will be start of burst // Makes sure next block will be start of burst
std::lock_guard<std::mutex> tx_lock(handler->tx_mutex);
if (handler->tx_state == RF_UHD_IMP_TX_STATE_WAIT_EOB_ACK) { if (handler->tx_state == RF_UHD_IMP_TX_STATE_WAIT_EOB_ACK) {
handler->tx_state = RF_UHD_IMP_TX_STATE_START_BURST; handler->tx_state = RF_UHD_IMP_TX_STATE_START_BURST;
} }
@ -1033,10 +1038,11 @@ double rf_uhd_set_rx_srate(void* h, double freq)
double rf_uhd_set_tx_srate(void* h, double freq) double rf_uhd_set_tx_srate(void* h, double freq)
{ {
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h; rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
std::unique_lock<std::mutex> lock(handler->tx_mutex); // Locking order should be kept the same with the async worker.
#if HAVE_ASYNC_THREAD #if HAVE_ASYNC_THREAD
std::unique_lock<std::mutex> lock_async(handler->async_mutex); std::unique_lock<std::mutex> lock_async(handler->async_mutex);
#endif /* HAVE_ASYNC_THREAD */ #endif /* HAVE_ASYNC_THREAD */
std::unique_lock<std::mutex> lock(handler->tx_mutex);
// Early return if the current rate matches and Tx stream has been created // Early return if the current rate matches and Tx stream has been created
if (freq == handler->tx_rate and handler->uhd->is_tx_ready()) { if (freq == handler->tx_rate and handler->uhd->is_tx_ready()) {
@ -1418,6 +1424,8 @@ int rf_uhd_send_timed_multi(void* h,
// Flush receiver only if allowed // Flush receiver only if allowed
if (RF_UHD_IMP_PROHIBITED_EOB_FLUSH.count(handler->devname) == 0) { if (RF_UHD_IMP_PROHIBITED_EOB_FLUSH.count(handler->devname) == 0) {
// Avoid holding the tx lock while in the rf_uhd_flush_buffer function to avoid potential deadlocks.
lock.unlock();
rf_uhd_flush_buffer(h); rf_uhd_flush_buffer(h);
} }

@ -170,7 +170,7 @@ int rf_zmq_rx_open(rf_zmq_rx_t* q, rf_zmq_opts_t opts, void* zmq_ctx, char* sock
} }
if (zmq_setsockopt(q->sock, ZMQ_SNDTIMEO, &timeout, sizeof(timeout)) == -1) { if (zmq_setsockopt(q->sock, ZMQ_SNDTIMEO, &timeout, sizeof(timeout)) == -1) {
fprintf(stderr, "Error: setting receive timeout on rx socket\n"); fprintf(stderr, "Error: setting send timeout on rx socket\n");
goto clean_exit; goto clean_exit;
} }

@ -66,7 +66,7 @@ int rf_zmq_tx_open(rf_zmq_tx_t* q, rf_zmq_opts_t opts, void* zmq_ctx, char* sock
} }
if (zmq_setsockopt(q->sock, ZMQ_SNDTIMEO, &timeout, sizeof(timeout)) == -1) { if (zmq_setsockopt(q->sock, ZMQ_SNDTIMEO, &timeout, sizeof(timeout)) == -1) {
fprintf(stderr, "Error: setting receive timeout on tx socket\n"); fprintf(stderr, "Error: setting send timeout on tx socket\n");
goto clean_exit; goto clean_exit;
} }

@ -567,10 +567,11 @@ int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* m
// Put PBCH DMRS // Put PBCH DMRS
srsran_dmrs_pbch_cfg_t pbch_dmrs_cfg = {}; srsran_dmrs_pbch_cfg_t pbch_dmrs_cfg = {};
pbch_dmrs_cfg.N_id = N_id; pbch_dmrs_cfg.N_id = N_id;
pbch_dmrs_cfg.n_hf = msg->hrf ? 0 : 1; pbch_dmrs_cfg.n_hf = msg->hrf ? 1 : 0;
pbch_dmrs_cfg.ssb_idx = msg->ssb_idx; pbch_dmrs_cfg.ssb_idx = msg->ssb_idx;
pbch_dmrs_cfg.L_max = q->Lmax; pbch_dmrs_cfg.L_max = q->Lmax;
pbch_dmrs_cfg.beta = 0.0f; pbch_dmrs_cfg.beta = 0.0f;
pbch_dmrs_cfg.scs = q->cfg.scs;
if (srsran_dmrs_pbch_put(&pbch_dmrs_cfg, ssb_grid) < SRSRAN_SUCCESS) { if (srsran_dmrs_pbch_put(&pbch_dmrs_cfg, ssb_grid) < SRSRAN_SUCCESS) {
ERROR("Error putting PBCH DMRS"); ERROR("Error putting PBCH DMRS");
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -579,7 +580,10 @@ int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* m
// Put PBCH payload // Put PBCH payload
srsran_pbch_nr_cfg_t pbch_cfg = {}; srsran_pbch_nr_cfg_t pbch_cfg = {};
pbch_cfg.N_id = N_id; pbch_cfg.N_id = N_id;
pbch_cfg.n_hf = msg->hrf;
pbch_cfg.ssb_idx = msg->ssb_idx;
pbch_cfg.Lmax = q->Lmax; pbch_cfg.Lmax = q->Lmax;
pbch_cfg.beta = 0.0f;
if (srsran_pbch_nr_encode(&q->pbch, &pbch_cfg, msg, ssb_grid) < SRSRAN_SUCCESS) { if (srsran_pbch_nr_encode(&q->pbch, &pbch_cfg, msg, ssb_grid) < SRSRAN_SUCCESS) {
ERROR("Error encoding PBCH"); ERROR("Error encoding PBCH");
return SRSRAN_ERROR; return SRSRAN_ERROR;

@ -145,15 +145,29 @@ target_link_libraries(ssb_measure_test srsran_phy)
add_executable(ssb_decode_test ssb_decode_test.c) add_executable(ssb_decode_test ssb_decode_test.c)
target_link_libraries(ssb_decode_test srsran_phy) target_link_libraries(ssb_decode_test srsran_phy)
# For each supported SSB subcarrier spacing # For 1.0 GHz and 3.5 GHz Center frequencies
foreach (SSB_SCS 15 30) foreach (CELL_FREQ 1000000 3500000)
# For each supported Cell/Carrier subcarrier spacing # For each supported Cell/Carrier subcarrier spacing
foreach (CELL_SCS 15 30) foreach (CELL_SCS 15 30)
# For SSB centered at -960, 0 and 960 kHz from the center frequency
foreach (SSB_OFFSET_FREQ -960 +0 +960)
# For each supported SSB subcarrier spacing
foreach (SSB_SCS 15 30)
# For patterns A, B, C
foreach (SSB_PATTERN A B C)
# Calculate Actual SSB center frequency
math(EXPR SSB_FREQ "${CELL_FREQ}${SSB_OFFSET_FREQ}")
# Test SSB measurements # Test SSB measurements
add_nr_test(ssb_measure_test_${SSB_SCS}_${CELL_SCS} ssb_measure_test -s ${SSB_SCS} -S ${CELL_SCS}) add_nr_test(ssb_measure_test_${CELL_FREQ}000_${CELL_SCS}_${SSB_FREQ}000_${SSB_SCS}_${SSB_PATTERN} ssb_measure_test
-F ${CELL_FREQ}000 -S ${CELL_SCS} -f ${SSB_FREQ}000 -s ${SSB_SCS} -P ${SSB_PATTERN})
# Test SSB PBCH decoding # Test SSB PBCH decoding
add_nr_test(ssb_decode_test_${SSB_SCS}_${CELL_SCS} ssb_decode_test -s ${SSB_SCS} -S ${CELL_SCS}) add_nr_test(ssb_decode_test_${CELL_FREQ}000_${CELL_SCS}_${SSB_FREQ}000_${SSB_SCS}_${SSB_PATTERN} ssb_decode_test
-F ${CELL_FREQ}000 -S ${CELL_SCS} -f ${SSB_FREQ}000 -s ${SSB_SCS} -P ${SSB_PATTERN})
endforeach ()
endforeach ()
endforeach ()
endforeach () endforeach ()
endforeach () endforeach ()

@ -32,7 +32,10 @@
// NR parameters // NR parameters
static uint32_t carrier_nof_prb = 52; static uint32_t carrier_nof_prb = 52;
static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_15kHz; static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_15kHz;
static double carrier_freq_hz = 3.5e9 + 960e3;
static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz; static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz;
static double ssb_freq_hz = 3.5e9;
static srsran_ssb_patern_t ssb_pattern = SRSRAN_SSB_PATTERN_A;
// Channel parameters // Channel parameters
static cf_t wideband_gain = 1.0f + 0.5 * I; static cf_t wideband_gain = 1.0f + 0.5 * I;
@ -51,14 +54,17 @@ static void usage(char* prog)
{ {
printf("Usage: %s [v]\n", prog); printf("Usage: %s [v]\n", prog);
printf("\t-s SSB subcarrier spacing [default, %s kHz]\n", srsran_subcarrier_spacing_to_str(ssb_scs)); printf("\t-s SSB subcarrier spacing [default, %s kHz]\n", srsran_subcarrier_spacing_to_str(ssb_scs));
printf("\t-f SSB center frequency [default, %.3f MHz]\n", ssb_freq_hz / 1e6);
printf("\t-S cell/carrier subcarrier spacing [default, %s kHz]\n", srsran_subcarrier_spacing_to_str(carrier_scs)); printf("\t-S cell/carrier subcarrier spacing [default, %s kHz]\n", srsran_subcarrier_spacing_to_str(carrier_scs));
printf("\t-F cell/carrier center frequency in Hz [default, %.3f MHz]\n", carrier_freq_hz / 1e6);
printf("\t-P SSB pattern [default, %s]\n", srsran_ssb_pattern_to_str(ssb_pattern));
printf("\t-v [set srsran_verbose to debug, default none]\n"); printf("\t-v [set srsran_verbose to debug, default none]\n");
} }
static void parse_args(int argc, char** argv) static void parse_args(int argc, char** argv)
{ {
int opt; int opt;
while ((opt = getopt(argc, argv, "Ssv")) != -1) { while ((opt = getopt(argc, argv, "SsFfPv")) != -1) {
switch (opt) { switch (opt) {
case 's': case 's':
ssb_scs = srsran_subcarrier_spacing_from_str(argv[optind]); ssb_scs = srsran_subcarrier_spacing_from_str(argv[optind]);
@ -67,6 +73,9 @@ static void parse_args(int argc, char** argv)
exit(-1); exit(-1);
} }
break; break;
case 'f':
ssb_freq_hz = strtod(argv[optind], NULL);
break;
case 'S': case 'S':
carrier_scs = srsran_subcarrier_spacing_from_str(argv[optind]); carrier_scs = srsran_subcarrier_spacing_from_str(argv[optind]);
if (carrier_scs == srsran_subcarrier_spacing_invalid) { if (carrier_scs == srsran_subcarrier_spacing_invalid) {
@ -74,6 +83,12 @@ static void parse_args(int argc, char** argv)
exit(-1); exit(-1);
} }
break; break;
case 'F':
carrier_freq_hz = strtod(argv[optind], NULL);
break;
case 'P':
ssb_pattern = srsran_ssb_pattern_fom_str(argv[optind]);
break;
case 'v': case 'v':
srsran_verbose++; srsran_verbose++;
break; break;
@ -123,10 +138,10 @@ static int test_case_1(srsran_ssb_t* ssb)
// SSB configuration // SSB configuration
srsran_ssb_cfg_t ssb_cfg = {}; srsran_ssb_cfg_t ssb_cfg = {};
ssb_cfg.srate_hz = srate_hz; ssb_cfg.srate_hz = srate_hz;
ssb_cfg.center_freq_hz = 3.5e9; ssb_cfg.center_freq_hz = carrier_freq_hz;
ssb_cfg.ssb_freq_hz = 3.5e9 - 960e3; ssb_cfg.ssb_freq_hz = ssb_freq_hz;
ssb_cfg.scs = ssb_scs; ssb_cfg.scs = ssb_scs;
ssb_cfg.pattern = SRSRAN_SSB_PATTERN_C; ssb_cfg.pattern = ssb_pattern;
TESTASSERT(srsran_ssb_set_cfg(ssb, &ssb_cfg) == SRSRAN_SUCCESS); TESTASSERT(srsran_ssb_set_cfg(ssb, &ssb_cfg) == SRSRAN_SUCCESS);

@ -30,10 +30,13 @@
// NR parameters // NR parameters
static uint32_t carrier_nof_prb = 52; static uint32_t carrier_nof_prb = 52;
static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_15kHz; static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_15kHz;
static double carrier_freq_hz = 3.5e9 + 960e3;
static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz; static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz;
static double ssb_freq_hz = 3.5e9;
static srsran_ssb_patern_t ssb_pattern = SRSRAN_SSB_PATTERN_A;
// Channel parameters // Channel parameters
static int32_t delay_n = 1; static int32_t delay_n = 2;
static float cfo_hz = 100.0f; static float cfo_hz = 100.0f;
static float n0_dB = -30.0f; static float n0_dB = -30.0f;
@ -46,8 +49,8 @@ static cf_t* buffer = NULL; // Base-band buffer
#define RSRP_MAX_ERROR 1.0f #define RSRP_MAX_ERROR 1.0f
#define EPRE_MAX_ERROR 1.0f #define EPRE_MAX_ERROR 1.0f
#define N0_MAX_ERROR 2.5f #define N0_MAX_ERROR 3.0f
#define SNR_MAX_ERROR 2.5f #define SNR_MAX_ERROR 3.0f
#define CFO_MAX_ERROR (cfo_hz * 0.3f) #define CFO_MAX_ERROR (cfo_hz * 0.3f)
#define DELAY_MAX_ERROR (delay_us * 0.1f) #define DELAY_MAX_ERROR (delay_us * 0.1f)
@ -55,14 +58,18 @@ static void usage(char* prog)
{ {
printf("Usage: %s [v]\n", prog); printf("Usage: %s [v]\n", prog);
printf("\t-s SSB subcarrier spacing [default, %s kHz]\n", srsran_subcarrier_spacing_to_str(ssb_scs)); printf("\t-s SSB subcarrier spacing [default, %s kHz]\n", srsran_subcarrier_spacing_to_str(ssb_scs));
printf("\t-f SSB center frequency [default, %.3f MHz]\n", ssb_freq_hz / 1e6);
printf("\t-S cell/carrier subcarrier spacing [default, %s kHz]\n", srsran_subcarrier_spacing_to_str(carrier_scs)); printf("\t-S cell/carrier subcarrier spacing [default, %s kHz]\n", srsran_subcarrier_spacing_to_str(carrier_scs));
printf("\t-F cell/carrier center frequency in Hz [default, %.3f MHz]\n", carrier_freq_hz / 1e6);
printf("\t-P SSB pattern [default, %s]\n", srsran_ssb_pattern_to_str(ssb_pattern));
printf("\t-v [set srsran_verbose to debug, default none]\n"); printf("\t-v [set srsran_verbose to debug, default none]\n");
} }
static void parse_args(int argc, char** argv) static void parse_args(int argc, char** argv)
{ {
int opt; int opt;
while ((opt = getopt(argc, argv, "Ssv")) != -1) { while ((opt = getopt(argc, argv, "SsFfPv")) != -1) {
switch (opt) { switch (opt) {
case 's': case 's':
ssb_scs = srsran_subcarrier_spacing_from_str(argv[optind]); ssb_scs = srsran_subcarrier_spacing_from_str(argv[optind]);
@ -71,6 +78,9 @@ static void parse_args(int argc, char** argv)
exit(-1); exit(-1);
} }
break; break;
case 'f':
ssb_freq_hz = strtod(argv[optind], NULL);
break;
case 'S': case 'S':
carrier_scs = srsran_subcarrier_spacing_from_str(argv[optind]); carrier_scs = srsran_subcarrier_spacing_from_str(argv[optind]);
if (carrier_scs == srsran_subcarrier_spacing_invalid) { if (carrier_scs == srsran_subcarrier_spacing_invalid) {
@ -78,6 +88,12 @@ static void parse_args(int argc, char** argv)
exit(-1); exit(-1);
} }
break; break;
case 'F':
carrier_freq_hz = strtod(argv[optind], NULL);
break;
case 'P':
ssb_pattern = srsran_ssb_pattern_fom_str(argv[optind]);
break;
case 'v': case 'v':
srsran_verbose++; srsran_verbose++;
break; break;
@ -123,10 +139,10 @@ static int test_case_1(srsran_ssb_t* ssb)
// SSB configuration // SSB configuration
srsran_ssb_cfg_t ssb_cfg = {}; srsran_ssb_cfg_t ssb_cfg = {};
ssb_cfg.srate_hz = srate_hz; ssb_cfg.srate_hz = srate_hz;
ssb_cfg.center_freq_hz = 3.5e9; ssb_cfg.center_freq_hz = carrier_freq_hz;
ssb_cfg.ssb_freq_hz = 3.5e9 - 960e3; ssb_cfg.ssb_freq_hz = ssb_freq_hz;
ssb_cfg.scs = ssb_scs; ssb_cfg.scs = ssb_scs;
ssb_cfg.pattern = SRSRAN_SSB_PATTERN_C; ssb_cfg.pattern = ssb_pattern;
TESTASSERT(srsran_ssb_set_cfg(ssb, &ssb_cfg) == SRSRAN_SUCCESS); TESTASSERT(srsran_ssb_set_cfg(ssb, &ssb_cfg) == SRSRAN_SUCCESS);
@ -228,6 +244,7 @@ int main(int argc, char** argv)
if (test_case_1(&ssb) != SRSRAN_SUCCESS) { if (test_case_1(&ssb) != SRSRAN_SUCCESS) {
ERROR("test case failed"); ERROR("test case failed");
goto clean_exit;
} }
ret = SRSRAN_SUCCESS; ret = SRSRAN_SUCCESS;

@ -585,19 +585,19 @@ int srsran_ue_dl_nr_decode_pdsch(srsran_ue_dl_nr_t* q,
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
int srsran_ue_dl_nr_pdsch_info(const srsran_ue_dl_nr_t* q, uint32_t srsran_ue_dl_nr_pdsch_info(const srsran_ue_dl_nr_t* q,
const srsran_sch_cfg_nr_t* cfg, const srsran_sch_cfg_nr_t* cfg,
const srsran_pdsch_res_nr_t res[SRSRAN_MAX_CODEWORDS], const srsran_pdsch_res_nr_t res[SRSRAN_MAX_CODEWORDS],
char* str, char* str,
uint32_t str_len) uint32_t str_len)
{ {
int len = 0; uint32_t len = 0;
// Append PDSCH info // Append PDSCH info
len += srsran_pdsch_nr_rx_info(&q->pdsch, cfg, &cfg->grant, res, &str[len], str_len - len); len += srsran_pdsch_nr_rx_info(&q->pdsch, cfg, &cfg->grant, res, &str[len], str_len - len);
// Append channel estimator info // Append channel estimator info
len = srsran_print_check(str, str_len, len, "SNR=%+.1f", q->chest.snr_db); len += srsran_csi_meas_info_short(&q->dmrs_pdsch.csi, &str[len], str_len - len);
return len; return len;
} }

@ -81,7 +81,7 @@ int srsran_ue_ul_nr_set_carrier(srsran_ue_ul_nr_t* q, const srsran_carrier_nr_t*
fft_cfg.nof_prb = carrier->nof_prb; fft_cfg.nof_prb = carrier->nof_prb;
fft_cfg.symbol_sz = srsran_min_symbol_sz_rb(carrier->nof_prb); fft_cfg.symbol_sz = srsran_min_symbol_sz_rb(carrier->nof_prb);
fft_cfg.keep_dc = true; fft_cfg.keep_dc = true;
fft_cfg.phase_compensation_hz = carrier->dl_center_frequency_hz; fft_cfg.phase_compensation_hz = carrier->ul_center_frequency_hz;
if (srsran_ofdm_tx_init_cfg(&q->ifft, &fft_cfg) < SRSRAN_SUCCESS) { if (srsran_ofdm_tx_init_cfg(&q->ifft, &fft_cfg) < SRSRAN_SUCCESS) {
ERROR("Initiating OFDM"); ERROR("Initiating OFDM");
return SRSRAN_ERROR; return SRSRAN_ERROR;

@ -714,7 +714,7 @@ void radio::set_rx_srate(const double& srate)
// Assert ratio is integer // Assert ratio is integer
srsran_assert(((uint32_t)cur_rx_srate % (uint32_t)srate) == 0, srsran_assert(((uint32_t)cur_rx_srate % (uint32_t)srate) == 0,
"The sampling rate ratio is not integer (%.2f MHz / %.2 MHz = %.3f)", "The sampling rate ratio is not integer (%.2f MHz / %.2f MHz = %.3f)",
cur_rx_srate / 1e6, cur_rx_srate / 1e6,
srate / 1e6, srate / 1e6,
cur_rx_srate / srate); cur_rx_srate / srate);
@ -967,7 +967,7 @@ void radio::set_tx_srate(const double& srate)
// Assert ratio is integer // Assert ratio is integer
srsran_assert(((uint32_t)cur_tx_srate % (uint32_t)srate) == 0, srsran_assert(((uint32_t)cur_tx_srate % (uint32_t)srate) == 0,
"The sampling rate ratio is not integer (%.2f MHz / %.2 MHz = %.3f)", "The sampling rate ratio is not integer (%.2f MHz / %.2f MHz = %.3f)",
cur_rx_srate / 1e6, cur_rx_srate / 1e6,
srate / 1e6, srate / 1e6,
cur_rx_srate / srate); cur_rx_srate / srate);

@ -0,0 +1,12 @@
#
# 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.
#
set(SOURCES emergency_handlers.cc
signal_handler.cc)
add_library(support STATIC ${SOURCES})

@ -0,0 +1,59 @@
/**
*
* \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 "srsran/support/emergency_handlers.h"
#include "srsran/support/srsran_assert.h"
namespace {
/// Holds the callback function pointer and the associated user provided data pointer.
struct handler_instance {
std::atomic<void*> data{};
std::atomic<emergency_cleanup_callback> callback{};
};
} // namespace
// Handlers are added in a thread safe manner without using locks to avoid possible issues if a signal is emitted while
// modifying the callback array.
static constexpr unsigned max_handlers = 12;
static handler_instance registered_handlers[max_handlers];
static std::atomic<unsigned> num_handlers;
void add_emergency_cleanup_handler(emergency_cleanup_callback callback, void* data)
{
// Reserve a slot in the array.
auto pos = num_handlers.fetch_add(1);
// Check if we have space in the array.
if (pos >= max_handlers) {
srsran_assert(0, "Exceeded the emergency cleanup handler registered limit");
return;
}
// Order is important here: write last the callback member as it is used to signal that the handler is valid when
// reading the array.
registered_handlers[pos].data.store(data);
registered_handlers[pos].callback.store(callback);
}
void execute_emergency_cleanup_handlers()
{
for (unsigned i = 0, e = num_handlers; i != e; ++i) {
auto callback = registered_handlers[i].callback.load();
// Test the validity of the callback as it may have not been written yet into the array even if num_callbacks has
// been updated.
if (callback) {
callback(registered_handlers[i].data.load());
}
}
}

@ -0,0 +1,54 @@
/**
*
* \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 "srsran/support/signal_handler.h"
#include "srsran/support/emergency_handlers.h"
#include <atomic>
#include <csignal>
#include <cstdio>
#include <unistd.h>
#define SRSRAN_TERM_TIMEOUT_S (5)
/// Handler called after the user interrupts the program.
static std::atomic<srsran_signal_hanlder> user_handler;
static void srsran_signal_handler(int signal)
{
switch (signal) {
case SIGALRM:
fprintf(stderr, "Couldn't stop after %ds. Forcing exit.\n", SRSRAN_TERM_TIMEOUT_S);
execute_emergency_cleanup_handlers();
raise(SIGKILL);
default:
// all other registered signals try to stop the app gracefully
// Call the user handler if present and remove it so that further signals are treated by the default handler.
if (auto handler = user_handler.exchange(nullptr)) {
handler();
} else {
return;
}
fprintf(stdout, "Stopping ..\n");
alarm(SRSRAN_TERM_TIMEOUT_S);
break;
}
}
void srsran_register_signal_handler(srsran_signal_hanlder handler)
{
user_handler.store(handler);
signal(SIGINT, srsran_signal_handler);
signal(SIGTERM, srsran_signal_handler);
signal(SIGHUP, srsran_signal_handler);
signal(SIGALRM, srsran_signal_handler);
}

@ -525,6 +525,90 @@ int mac_ul_sch_pdu_unpack_and_pack_test3()
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
int mac_ul_sch_pdu_unpack_and_pack_test4()
{
// MAC PDU with UL-SCH with C-RNTI, Long BSR (all zeros) and padding
uint8_t mac_ul_sch_pdu_1[] = {0x3a, 0x46, 0x01, 0x3e, 0x01, 0x00, 0x3f, 0x21, 0x21, 0x21, 0x21};
const uint16_t TV_CRNTI = 0x4601;
// only LBSR with only one LCG (LCG7 leftmost bit) reporting buffer state
uint8_t mac_ul_sch_pdu_2[] = {0x3e, 0x02, 0x80, 0xab};
// only LBSR with only two LCG (LCG7 leftmost bit. LCG0) reporting buffer state
uint8_t mac_ul_sch_pdu_3[] = {0x3e, 0x03, 0x81, 0xab, 0xcd};
if (pcap_handle) {
pcap_handle->write_ul_crnti_nr(mac_ul_sch_pdu_1, sizeof(mac_ul_sch_pdu_1), PCAP_CRNTI, true, PCAP_TTI);
pcap_handle->write_ul_crnti_nr(mac_ul_sch_pdu_2, sizeof(mac_ul_sch_pdu_2), PCAP_CRNTI, true, PCAP_TTI);
pcap_handle->write_ul_crnti_nr(mac_ul_sch_pdu_3, sizeof(mac_ul_sch_pdu_3), PCAP_CRNTI, true, PCAP_TTI);
}
// pretty print PDU
fmt::memory_buffer buff;
auto& mac_logger = srslog::fetch_basic_logger("MAC");
// first TV
srsran::mac_sch_pdu_nr pdu(true);
pdu.unpack(mac_ul_sch_pdu_1, sizeof(mac_ul_sch_pdu_1));
pdu.to_string(buff);
mac_logger.info("Rx PDU: %s", srsran::to_c_str(buff));
TESTASSERT(pdu.get_num_subpdus() == 3);
// 1st subPDU is C-RNTI CE
mac_sch_subpdu_nr subpdu = pdu.get_subpdu(0);
TESTASSERT(subpdu.get_total_length() == 3);
TESTASSERT(subpdu.get_sdu_length() == 2);
TESTASSERT(subpdu.get_lcid() == mac_sch_subpdu_nr::CRNTI);
TESTASSERT(subpdu.get_c_rnti() == TV_CRNTI);
// 2nd subPDU is LBSR
subpdu = pdu.get_subpdu(1);
TESTASSERT(subpdu.get_lcid() == mac_sch_subpdu_nr::LONG_BSR);
mac_sch_subpdu_nr::lbsr_t lbsr = subpdu.get_lbsr();
TESTASSERT(lbsr.list.size() == 0);
// 3rd is padding
subpdu = pdu.get_subpdu(2);
TESTASSERT(subpdu.get_lcid() == mac_sch_subpdu_nr::PADDING);
// TODO: pack again and test
// 2nd TV
pdu.init_rx(true);
pdu.unpack(mac_ul_sch_pdu_2, sizeof(mac_ul_sch_pdu_2));
buff.clear();
pdu.to_string(buff);
mac_logger.info("Rx PDU: %s", srsran::to_c_str(buff));
TESTASSERT(pdu.get_num_subpdus() == 1);
subpdu = pdu.get_subpdu(0);
TESTASSERT(subpdu.get_lcid() == mac_sch_subpdu_nr::LONG_BSR);
lbsr = subpdu.get_lbsr();
TESTASSERT(lbsr.list.size() == 1);
TESTASSERT(lbsr.list.at(0).lcg_id == 7);
TESTASSERT(lbsr.list.at(0).buffer_size == 0xab);
// 3nd TV
pdu.init_rx(true);
pdu.unpack(mac_ul_sch_pdu_3, sizeof(mac_ul_sch_pdu_3));
buff.clear();
pdu.to_string(buff);
mac_logger.info("Rx PDU: %s", srsran::to_c_str(buff));
TESTASSERT(pdu.get_num_subpdus() == 1);
subpdu = pdu.get_subpdu(0);
TESTASSERT(subpdu.get_lcid() == mac_sch_subpdu_nr::LONG_BSR);
lbsr = subpdu.get_lbsr();
TESTASSERT(lbsr.list.size() == 2);
TESTASSERT(lbsr.list.at(0).lcg_id == 0);
TESTASSERT(lbsr.list.at(0).buffer_size == 0xab);
TESTASSERT(lbsr.list.at(1).lcg_id == 7);
TESTASSERT(lbsr.list.at(1).buffer_size == 0xcd);
return SRSRAN_SUCCESS;
}
int mac_ul_sch_pdu_pack_test4() int mac_ul_sch_pdu_pack_test4()
{ {
// MAC PDU with UL-SCH (with normal LCID) subheader for long SDU // MAC PDU with UL-SCH (with normal LCID) subheader for long SDU
@ -780,6 +864,11 @@ int main(int argc, char** argv)
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
if (mac_ul_sch_pdu_unpack_and_pack_test4()) {
fprintf(stderr, "mac_ul_sch_pdu_unpack_and_pack_test4() failed.\n");
return SRSRAN_ERROR;
}
if (mac_ul_sch_pdu_pack_test4()) { if (mac_ul_sch_pdu_pack_test4()) {
fprintf(stderr, "mac_ul_sch_pdu_pack_test4() failed.\n"); fprintf(stderr, "mac_ul_sch_pdu_pack_test4() failed.\n");
return SRSRAN_ERROR; return SRSRAN_ERROR;

@ -82,7 +82,7 @@ foreach(rb 25 52 79 106 133 160 216 270)
add_nr_test(phy_dl_nr_test_${rb}prb_interleaved phy_dl_nr_test -P ${rb} -p 25 -m 10 -I) add_nr_test(phy_dl_nr_test_${rb}prb_interleaved phy_dl_nr_test -P ${rb} -p 25 -m 10 -I)
# Maximum throughput with 256QAM # Maximum throughput with 256QAM
add_nr_test(phy_dl_nr_test_${rb}prb_256qam phy_dl_nr_test -P ${rb} -p ${rb} -m 27 -T 256qam -v -d 1 1 -n 10) add_nr_test(phy_dl_nr_test_${rb}prb_256qam phy_dl_nr_test -P ${rb} -p ${rb} -m 27 -T 256qam -v -d 1 1 1 -n 10)
# Maximum throughput with 64QAM and CFO+Delay impairments # Maximum throughput with 64QAM and CFO+Delay impairments
add_nr_test(phy_dl_nr_test_${rb}prb_cfo_delay phy_dl_nr_test -P ${rb} -p ${rb} -m 27 -C 100.0 -D 4 -n 10) add_nr_test(phy_dl_nr_test_${rb}prb_cfo_delay phy_dl_nr_test -P ${rb} -p ${rb} -m 27 -C 100.0 -D 4 -n 10)

@ -39,6 +39,7 @@ static float cfo_hz = 0.0f; // CFO Hz
static srsran_dmrs_sch_type_t dmrs_type = srsran_dmrs_sch_type_1; static srsran_dmrs_sch_type_t dmrs_type = srsran_dmrs_sch_type_1;
static srsran_dmrs_sch_add_pos_t dmrs_add_pos = srsran_dmrs_sch_add_pos_2; static srsran_dmrs_sch_add_pos_t dmrs_add_pos = srsran_dmrs_sch_add_pos_2;
static bool interleaved_pdcch = false; static bool interleaved_pdcch = false;
static uint32_t nof_dmrs_cdm_groups_without_data = 1;
static void usage(char* prog) static void usage(char* prog)
{ {
@ -88,7 +89,7 @@ static int parse_args(int argc, char** argv)
dmrs_type = srsran_dmrs_sch_type_2; dmrs_type = srsran_dmrs_sch_type_2;
break; break;
} }
switch (strtol(argv[optind], NULL, 10)) { switch (strtol(argv[optind++], NULL, 10)) {
case 0: case 0:
dmrs_add_pos = srsran_dmrs_sch_add_pos_0; dmrs_add_pos = srsran_dmrs_sch_add_pos_0;
break; break;
@ -102,6 +103,7 @@ static int parse_args(int argc, char** argv)
dmrs_add_pos = srsran_dmrs_sch_add_pos_3; dmrs_add_pos = srsran_dmrs_sch_add_pos_3;
break; break;
} }
nof_dmrs_cdm_groups_without_data = (uint32_t)strtol(argv[optind], NULL, 10);
break; break;
case 'T': case 'T':
pdsch_cfg.sch_cfg.mcs_table = srsran_mcs_table_from_str(argv[optind]); pdsch_cfg.sch_cfg.mcs_table = srsran_mcs_table_from_str(argv[optind]);
@ -366,7 +368,7 @@ int main(int argc, char** argv)
pdsch_cfg.grant.L = 13; pdsch_cfg.grant.L = 13;
pdsch_cfg.grant.nof_layers = carrier.max_mimo_layers; pdsch_cfg.grant.nof_layers = carrier.max_mimo_layers;
pdsch_cfg.grant.dci_format = srsran_dci_format_nr_1_0; pdsch_cfg.grant.dci_format = srsran_dci_format_nr_1_0;
pdsch_cfg.grant.nof_dmrs_cdm_groups_without_data = 1; pdsch_cfg.grant.nof_dmrs_cdm_groups_without_data = nof_dmrs_cdm_groups_without_data;
pdsch_cfg.grant.beta_dmrs = srsran_convert_dB_to_amplitude(3); pdsch_cfg.grant.beta_dmrs = srsran_convert_dB_to_amplitude(3);
pdsch_cfg.grant.rnti_type = srsran_rnti_type_c; pdsch_cfg.grant.rnti_type = srsran_rnti_type_c;
pdsch_cfg.grant.rnti = 0x4601; pdsch_cfg.grant.rnti = 0x4601;

@ -186,6 +186,8 @@ enable = false
# init_dl_cqi: DL CQI value used before any CQI report is available to the eNB # init_dl_cqi: DL CQI value used before any CQI report is available to the eNB
# max_sib_coderate: Upper bound on SIB and RAR grants coderate # max_sib_coderate: Upper bound on SIB and RAR grants coderate
# pdcch_cqi_offset: CQI offset in derivation of PDCCH aggregation level # pdcch_cqi_offset: CQI offset in derivation of PDCCH aggregation level
# nr_pdsch_mcs: Optional fixed NR PDSCH MCS (ignores reported CQIs if specified)
# nr_pusch_mcs: Optional fixed NR PUSCH MCS (ignores reported CQIs if specified)
# #
##################################################################### #####################################################################
[scheduler] [scheduler]
@ -213,6 +215,8 @@ enable = false
#init_dl_cqi=5 #init_dl_cqi=5
#max_sib_coderate=0.3 #max_sib_coderate=0.3
#pdcch_cqi_offset=0 #pdcch_cqi_offset=0
#nr_pdsch_mcs=28
#nr_pusch_mcs=28
##################################################################### #####################################################################
# eMBMS configuration options # eMBMS configuration options
@ -324,7 +328,8 @@ enable = false
##################################################################### #####################################################################
# Expert configuration options # Expert configuration options
# #
# pusch_max_its: Maximum number of turbo decoder iterations (Default 4) # pusch_max_its: Maximum number of turbo decoder iterations for LTE (Default 4)
# nr_pusch_max_its: Maximum number of LDPC iterations for NR (Default 10)
# pusch_8bit_decoder: Use 8-bit for LLR representation and turbo decoder trellis computation (Experimental) # pusch_8bit_decoder: Use 8-bit for LLR representation and turbo decoder trellis computation (Experimental)
# nof_phy_threads: Selects the number of PHY threads (maximum 4, minimum 1, default 3) # nof_phy_threads: Selects the number of PHY threads (maximum 4, minimum 1, default 3)
# metrics_period_secs: Sets the period at which metrics are requested from the eNB. # metrics_period_secs: Sets the period at which metrics are requested from the eNB.
@ -358,6 +363,7 @@ enable = false
##################################################################### #####################################################################
[expert] [expert]
#pusch_max_its = 8 # These are half iterations #pusch_max_its = 8 # These are half iterations
#nr_pusch_max_its = 10
#pusch_8bit_decoder = false #pusch_8bit_decoder = false
#nof_phy_threads = 3 #nof_phy_threads = 3
#metrics_period_secs = 1 #metrics_period_secs = 1

@ -33,15 +33,14 @@
#include <string> #include <string>
#include "phy/phy.h" #include "phy/phy.h"
#include "x2_adapter.h"
#include "srsran/radio/radio.h" #include "srsran/radio/radio.h"
#include "srsenb/hdr/phy/enb_phy_base.h" #include "srsenb/hdr/phy/enb_phy_base.h"
#include "srsenb/hdr/stack/enb_stack_base.h" #include "srsenb/hdr/stack/enb_stack_base.h"
#include "srsenb/hdr/stack/rrc/nr/rrc_config_nr.h"
#include "srsenb/hdr/stack/rrc/rrc_config.h" #include "srsenb/hdr/stack/rrc/rrc_config.h"
#include "srsenb/hdr/stack/gnb_stack_nr.h"
#include "srsenb/hdr/stack/mac/sched_interface.h" #include "srsenb/hdr/stack/mac/sched_interface.h"
#include "srsran/common/bcd_helpers.h" #include "srsran/common/bcd_helpers.h"
#include "srsran/common/buffer_pool.h" #include "srsran/common/buffer_pool.h"
@ -51,6 +50,7 @@
#include "srsran/interfaces/enb_command_interface.h" #include "srsran/interfaces/enb_command_interface.h"
#include "srsran/interfaces/enb_metrics_interface.h" #include "srsran/interfaces/enb_metrics_interface.h"
#include "srsran/interfaces/enb_time_interface.h" #include "srsran/interfaces/enb_time_interface.h"
#include "srsran/interfaces/enb_x2_interfaces.h"
#include "srsran/interfaces/ue_interfaces.h" #include "srsran/interfaces/ue_interfaces.h"
#include "srsran/srslog/srslog.h" #include "srsran/srslog/srslog.h"
#include "srsran/system/sys_metrics_processor.h" #include "srsran/system/sys_metrics_processor.h"
@ -121,6 +121,7 @@ struct all_args_t {
general_args_t general; general_args_t general;
phy_args_t phy; phy_args_t phy;
stack_args_t stack; stack_args_t stack;
gnb_stack_args_t nr_stack;
}; };
struct rrc_cfg_t; struct rrc_cfg_t;
@ -170,7 +171,7 @@ private:
rrc_nr_cfg_t rrc_nr_cfg = {}; rrc_nr_cfg_t rrc_nr_cfg = {};
// eNB components // eNB components
x2_adapter x2; std::unique_ptr<x2_interface> x2;
std::unique_ptr<enb_stack_base> eutra_stack = nullptr; std::unique_ptr<enb_stack_base> eutra_stack = nullptr;
std::unique_ptr<enb_stack_base> nr_stack = nullptr; std::unique_ptr<enb_stack_base> nr_stack = nullptr;
std::unique_ptr<srsran::radio_base> radio = nullptr; std::unique_ptr<srsran::radio_base> radio = nullptr;

@ -65,7 +65,8 @@ public:
uint32_t nof_rx_ports = 1; uint32_t nof_rx_ports = 1;
uint32_t rf_port = 0; uint32_t rf_port = 0;
srsran_subcarrier_spacing_t scs = srsran_subcarrier_spacing_15kHz; srsran_subcarrier_spacing_t scs = srsran_subcarrier_spacing_15kHz;
uint32_t pusch_max_nof_iter = 10; uint32_t pusch_max_its = 10;
float pusch_min_snr_dB = -10.0f;
double srate_hz = 0.0; double srate_hz = 0.0;
}; };

@ -111,7 +111,8 @@ public:
uint32_t nof_phy_threads = 3; uint32_t nof_phy_threads = 3;
uint32_t nof_prach_workers = 0; uint32_t nof_prach_workers = 0;
uint32_t prio = 52; uint32_t prio = 52;
uint32_t pusch_max_nof_iter = 10; uint32_t pusch_max_its = 10;
float pusch_min_snr_dB = -10;
srsran::phy_log_args_t log = {}; srsran::phy_log_args_t log = {};
}; };
slot_worker* operator[](std::size_t pos) { return workers.at(pos).get(); } slot_worker* operator[](std::size_t pos) { return workers.at(pos).get(); }

@ -47,13 +47,13 @@ public:
int init(const phy_args_t& args, int init(const phy_args_t& args,
const phy_cfg_t& cfg, const phy_cfg_t& cfg,
srsran::radio_interface_phy* radio_, srsran::radio_interface_phy* radio_,
stack_interface_phy_lte* stack_, stack_interface_phy_lte* stack_lte_,
stack_interface_phy_nr& stack_nr_,
enb_time_interface* enb_); enb_time_interface* enb_);
int init(const phy_args_t& args, int init(const phy_args_t& args,
const phy_cfg_t& cfg, const phy_cfg_t& cfg,
srsran::radio_interface_phy* radio_, srsran::radio_interface_phy* radio_,
stack_interface_phy_lte* stack_lte_, stack_interface_phy_lte* stack_,
stack_interface_phy_nr& stack_nr_,
enb_time_interface* enb_); enb_time_interface* enb_);
void stop() override; void stop() override;
@ -81,7 +81,6 @@ public:
void srsran_phy_logger(phy_logger_level_t log_level, char* str); void srsran_phy_logger(phy_logger_level_t log_level, char* str);
int init_nr(const phy_args_t& args, const phy_cfg_t& cfg, stack_interface_phy_nr& stack);
int set_common_cfg(const common_cfg_t& common_cfg) override; int set_common_cfg(const common_cfg_t& common_cfg) override;
private: private:
@ -112,6 +111,12 @@ private:
common_cfg_t common_cfg = {}; common_cfg_t common_cfg = {};
void parse_common_config(const phy_cfg_t& cfg); void parse_common_config(const phy_cfg_t& cfg);
int init_lte(const phy_args_t& args,
const phy_cfg_t& cfg,
srsran::radio_interface_phy* radio_,
stack_interface_phy_lte* stack_,
enb_time_interface* enb_);
int init_nr(const phy_args_t& args, const phy_cfg_t& cfg, stack_interface_phy_nr& stack);
}; };
} // namespace srsenb } // namespace srsenb

@ -71,9 +71,9 @@ public:
// Common objects // Common objects
phy_args_t params = {}; phy_args_t params = {};
uint32_t get_nof_carriers_lte() { return static_cast<uint32_t>(cell_list_lte.size()); }; uint32_t get_nof_carriers_lte() { return static_cast<uint32_t>(cell_list_lte.size()); }
uint32_t get_nof_carriers_nr() { return static_cast<uint32_t>(cell_list_nr.size()); }; uint32_t get_nof_carriers_nr() { return static_cast<uint32_t>(cell_list_nr.size()); }
uint32_t get_nof_carriers() { return static_cast<uint32_t>(cell_list_lte.size() + cell_list_nr.size()); }; uint32_t get_nof_carriers() { return static_cast<uint32_t>(cell_list_lte.size() + cell_list_nr.size()); }
uint32_t get_nof_prb(uint32_t cc_idx) uint32_t get_nof_prb(uint32_t cc_idx)
{ {
uint32_t ret = 0; uint32_t ret = 0;
@ -93,7 +93,7 @@ public:
} }
} }
return ret; return ret;
}; }
uint32_t get_nof_ports(uint32_t cc_idx) uint32_t get_nof_ports(uint32_t cc_idx)
{ {
uint32_t ret = 0; uint32_t ret = 0;
@ -106,7 +106,7 @@ public:
} }
return ret; return ret;
}; }
uint32_t get_nof_rf_channels() uint32_t get_nof_rf_channels()
{ {
uint32_t count = 0; uint32_t count = 0;
@ -135,7 +135,7 @@ public:
} }
return ret; return ret;
}; }
double get_dl_freq_hz(uint32_t cc_idx) double get_dl_freq_hz(uint32_t cc_idx)
{ {
double ret = 0.0; double ret = 0.0;
@ -150,7 +150,7 @@ public:
} }
return ret; return ret;
}; }
uint32_t get_rf_port(uint32_t cc_idx) uint32_t get_rf_port(uint32_t cc_idx)
{ {
uint32_t ret = 0; uint32_t ret = 0;
@ -165,7 +165,7 @@ public:
} }
return ret; return ret;
}; }
srsran_cell_t get_cell(uint32_t cc_idx) srsran_cell_t get_cell(uint32_t cc_idx)
{ {
srsran_cell_t c = {}; srsran_cell_t c = {};
@ -173,7 +173,7 @@ public:
c = cell_list_lte[cc_idx].cell; c = cell_list_lte[cc_idx].cell;
} }
return c; return c;
}; }
void set_cell_gain(uint32_t cell_id, float gain_db) void set_cell_gain(uint32_t cell_id, float gain_db)
{ {
@ -183,6 +183,7 @@ public:
// Check if the lte cell was found; // Check if the lte cell was found;
if (it_lte != cell_list_lte.end()) { if (it_lte != cell_list_lte.end()) {
std::lock_guard<std::mutex> lock(cell_gain_mutex);
it_lte->gain_db = gain_db; it_lte->gain_db = gain_db;
return; return;
} }
@ -193,6 +194,7 @@ public:
// Check if the nr cell was found; // Check if the nr cell was found;
if (it_nr != cell_list_nr.end()) { if (it_nr != cell_list_nr.end()) {
std::lock_guard<std::mutex> lock(cell_gain_mutex);
it_nr->gain_db = gain_db; it_nr->gain_db = gain_db;
return; return;
} }
@ -202,6 +204,7 @@ public:
float get_cell_gain(uint32_t cc_idx) float get_cell_gain(uint32_t cc_idx)
{ {
std::lock_guard<std::mutex> lock(cell_gain_mutex);
if (cc_idx < cell_list_lte.size()) { if (cc_idx < cell_list_lte.size()) {
return cell_list_lte.at(cc_idx).gain_db; return cell_list_lte.at(cc_idx).gain_db;
} }
@ -244,6 +247,7 @@ private:
phy_cell_cfg_list_t cell_list_lte; phy_cell_cfg_list_t cell_list_lte;
phy_cell_cfg_list_nr_t cell_list_nr; phy_cell_cfg_list_nr_t cell_list_nr;
std::mutex cell_gain_mutex;
bool have_mtch_stop = false; bool have_mtch_stop = false;
pthread_mutex_t mtch_mutex = {}; pthread_mutex_t mtch_mutex = {};

@ -63,7 +63,8 @@ struct phy_args_t {
srsran::phy_log_args_t log; srsran::phy_log_args_t log;
float max_prach_offset_us = 10; float max_prach_offset_us = 10;
int pusch_max_its = 10; uint32_t pusch_max_its = 10;
uint32_t nr_pusch_max_its = 10;
bool pusch_8bit_decoder = false; bool pusch_8bit_decoder = false;
float tx_amplitude = 1.0f; float tx_amplitude = 1.0f;
uint32_t nof_phy_threads = 1; uint32_t nof_phy_threads = 1;

@ -135,6 +135,10 @@ public:
// Note: RRC processes activity asynchronously, so there is no need to use x2_task_queue // Note: RRC processes activity asynchronously, so there is no need to use x2_task_queue
rrc.set_activity_user(eutra_rnti); rrc.set_activity_user(eutra_rnti);
} }
void sgnb_release_ack(uint16_t eutra_rnti) final
{
x2_task_queue.push([this, eutra_rnti]() { rrc.sgnb_release_ack(eutra_rnti); });
}
// gtpu_interface_pdcp // gtpu_interface_pdcp
void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu); void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu);

@ -38,6 +38,11 @@
namespace srsenb { namespace srsenb {
struct gnb_stack_args_t {
stack_log_args_t log;
mac_nr_args_t mac;
};
class gnb_stack_nr final : public srsenb::enb_stack_base, class gnb_stack_nr final : public srsenb::enb_stack_base,
public stack_interface_phy_nr, public stack_interface_phy_nr,
public stack_interface_mac, public stack_interface_mac,
@ -50,7 +55,7 @@ public:
explicit gnb_stack_nr(srslog::sink& log_sink); explicit gnb_stack_nr(srslog::sink& log_sink);
~gnb_stack_nr() final; ~gnb_stack_nr() final;
int init(const srsenb::stack_args_t& args_, int init(const gnb_stack_args_t& args_,
const rrc_nr_cfg_t& rrc_cfg_, const rrc_nr_cfg_t& rrc_cfg_,
phy_interface_stack_nr* phy_, phy_interface_stack_nr* phy_,
x2_interface* x2_); x2_interface* x2_);
@ -85,14 +90,19 @@ public:
// X2 interface // X2 interface
// control plane, i.e. rrc_nr_interface_rrc // control plane, i.e. rrc_nr_interface_rrc
int sgnb_addition_request(uint16_t eutra_rnti, const sgnb_addition_req_params_t& params) final void sgnb_addition_request(uint16_t eutra_rnti, const sgnb_addition_req_params_t& params) final
{ {
return rrc.sgnb_addition_request(eutra_rnti, params); x2_task_queue.push([this, eutra_rnti, params]() { rrc.sgnb_addition_request(eutra_rnti, params); });
}; };
int sgnb_reconfiguration_complete(uint16_t eutra_rnti, asn1::dyn_octstring reconfig_response) final void sgnb_reconfiguration_complete(uint16_t eutra_rnti, const asn1::dyn_octstring& reconfig_response) final
{ {
return rrc.sgnb_reconfiguration_complete(eutra_rnti, reconfig_response); x2_task_queue.push(
[this, eutra_rnti, reconfig_response]() { rrc.sgnb_reconfiguration_complete(eutra_rnti, reconfig_response); });
}; };
void sgnb_release_request(uint16_t nr_rnti) final
{
x2_task_queue.push([this, nr_rnti]() { return rrc.sgnb_release_request(nr_rnti); });
}
// X2 data interface // X2 data interface
void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu, int pdcp_sn = -1) final void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu, int pdcp_sn = -1) final
{ {
@ -110,9 +120,10 @@ public:
private: private:
void run_thread() final; void run_thread() final;
void tti_clock_impl(); void tti_clock_impl();
void stop_impl();
// args // args
srsenb::stack_args_t args = {}; gnb_stack_args_t args = {};
phy_interface_stack_nr* phy = nullptr; phy_interface_stack_nr* phy = nullptr;
srslog::basic_logger& rrc_logger; srslog::basic_logger& rrc_logger;
@ -124,7 +135,12 @@ private:
// task scheduling // task scheduling
static const int STACK_MAIN_THREAD_PRIO = 4; static const int STACK_MAIN_THREAD_PRIO = 4;
srsran::task_scheduler task_sched; srsran::task_scheduler task_sched;
srsran::task_multiqueue::queue_handle sync_task_queue, ue_task_queue, gtpu_task_queue, mac_task_queue; srsran::task_multiqueue::queue_handle sync_task_queue, gtpu_task_queue, metrics_task_queue, gnb_task_queue,
x2_task_queue;
// metrics waiting condition
std::mutex metrics_mutex;
std::condition_variable metrics_cvar;
// derived // derived
srsenb::mac_nr mac; srsenb::mac_nr mac;

@ -164,12 +164,12 @@ private:
const static int NOF_BCCH_DLSCH_MSG = sched_interface::MAX_SIBS; const static int NOF_BCCH_DLSCH_MSG = sched_interface::MAX_SIBS;
const static int pcch_payload_buffer_len = 1024; const static int pcch_payload_buffer_len = 1024;
typedef struct { struct common_buffers_t {
uint8_t pcch_payload_buffer[pcch_payload_buffer_len] = {}; uint8_t pcch_payload_buffer[pcch_payload_buffer_len] = {};
srsran_softbuffer_tx_t bcch_softbuffer_tx[NOF_BCCH_DLSCH_MSG] = {}; srsran_softbuffer_tx_t bcch_softbuffer_tx[NOF_BCCH_DLSCH_MSG] = {};
srsran_softbuffer_tx_t pcch_softbuffer_tx = {}; srsran_softbuffer_tx_t pcch_softbuffer_tx = {};
srsran_softbuffer_tx_t rar_softbuffer_tx = {}; srsran_softbuffer_tx_t rar_softbuffer_tx = {};
} common_buffers_t; };
std::vector<common_buffers_t> common_buffers; std::vector<common_buffers_t> common_buffers;

@ -40,7 +40,7 @@ struct mac_nr_args_t {
srsran::phy_cfg_nr_t phy_base_cfg = {}; srsran::phy_cfg_nr_t phy_base_cfg = {};
int fixed_dl_mcs = -1; int fixed_dl_mcs = -1;
int fixed_ul_mcs = -1; int fixed_ul_mcs = -1;
sched_nr_interface::sched_cfg_t sched_cfg = {}; sched_nr_interface::sched_args_t sched_cfg = {};
srsenb::pcap_args_t pcap; srsenb::pcap_args_t pcap;
}; };
@ -57,11 +57,12 @@ public:
rrc_interface_mac_nr* rrc_); rrc_interface_mac_nr* rrc_);
void stop(); void stop();
/// Called from metrics thread.
void get_metrics(srsenb::mac_metrics_t& metrics); void get_metrics(srsenb::mac_metrics_t& metrics);
// MAC interface for RRC // MAC interface for RRC
int cell_cfg(const std::vector<srsenb::sched_nr_interface::cell_cfg_t>& nr_cells) override; int cell_cfg(const std::vector<srsenb::sched_nr_interface::cell_cfg_t>& nr_cells) override;
uint16_t reserve_rnti(uint32_t enb_cc_idx) override; uint16_t reserve_rnti(uint32_t enb_cc_idx, const sched_nr_interface::ue_cfg_t& uecfg) override;
int read_pdu_bcch_bch(uint8_t* payload); int read_pdu_bcch_bch(uint8_t* payload);
int ue_cfg(uint16_t rnti, const sched_nr_interface::ue_cfg_t& ue_cfg) override; int ue_cfg(uint16_t rnti, const sched_nr_interface::ue_cfg_t& ue_cfg) override;
int remove_ue(uint16_t rnti) override; int remove_ue(uint16_t rnti) override;
@ -91,8 +92,11 @@ private:
// PDU processing // PDU processing
int handle_pdu(srsran::unique_byte_buffer_t pdu); int handle_pdu(srsran::unique_byte_buffer_t pdu);
// Metrics processing
void get_metrics_nolock(srsenb::mac_metrics_t& metrics);
// Encoding // Encoding
srsran::byte_buffer_t* assemble_rar(srsran::const_span<sched_nr_interface::sched_rar_grant_t> grants); srsran::byte_buffer_t* assemble_rar(srsran::const_span<sched_nr_interface::msg3_grant_t> grants);
srsran::unique_byte_buffer_t rar_pdu_buffer = nullptr; srsran::unique_byte_buffer_t rar_pdu_buffer = nullptr;
// Interaction with other components // Interaction with other components
@ -116,7 +120,7 @@ private:
std::vector<sched_nr_interface::cell_cfg_t> cell_config; std::vector<sched_nr_interface::cell_cfg_t> cell_config;
// Map of active UEs // Map of active UEs
pthread_rwlock_t rwlock = {}; pthread_rwlock_t rwmutex = {};
static const uint16_t FIRST_RNTI = 0x4601; static const uint16_t FIRST_RNTI = 0x4601;
srsran::static_circular_map<uint16_t, std::unique_ptr<ue_nr>, SRSENB_MAX_UES> ue_db; srsran::static_circular_map<uint16_t, std::unique_ptr<ue_nr>, SRSENB_MAX_UES> ue_db;

@ -39,7 +39,6 @@ class sched_worker_manager;
class serv_cell_manager; class serv_cell_manager;
} // namespace sched_nr_impl } // namespace sched_nr_impl
class ue_event_manager;
class ul_sched_result_buffer; class ul_sched_result_buffer;
class sched_nr final : public sched_nr_interface class sched_nr final : public sched_nr_interface
@ -47,12 +46,12 @@ class sched_nr final : public sched_nr_interface
public: public:
explicit sched_nr(); explicit sched_nr();
~sched_nr() override; ~sched_nr() override;
int config(const sched_cfg_t& sched_cfg, srsran::const_span<cell_cfg_t> cell_list) override; int config(const sched_args_t& sched_cfg, srsran::const_span<cell_cfg_t> cell_list) override;
void ue_cfg(uint16_t rnti, const ue_cfg_t& cfg) override; void ue_cfg(uint16_t rnti, const ue_cfg_t& cfg) override;
void ue_rem(uint16_t rnti) override; void ue_rem(uint16_t rnti) override;
bool ue_exists(uint16_t rnti) override; bool ue_exists(uint16_t rnti) override;
int dl_rach_info(uint32_t cc, const dl_sched_rar_info_t& rar_info); int dl_rach_info(uint32_t cc, const rar_info_t& rar_info);
void dl_ack_info(uint16_t rnti, uint32_t cc, uint32_t pid, uint32_t tb_idx, bool ack) override; void dl_ack_info(uint16_t rnti, uint32_t cc, uint32_t pid, uint32_t tb_idx, bool ack) override;
void ul_crc_info(uint16_t rnti, uint32_t cc, uint32_t pid, bool crc) override; void ul_crc_info(uint16_t rnti, uint32_t cc, uint32_t pid, bool crc) override;
@ -60,9 +59,11 @@ public:
void ul_bsr(uint16_t rnti, uint32_t lcg_id, uint32_t bsr) override; void ul_bsr(uint16_t rnti, uint32_t lcg_id, uint32_t bsr) override;
void dl_buffer_state(uint16_t rnti, uint32_t lcid, uint32_t newtx, uint32_t retx); void dl_buffer_state(uint16_t rnti, uint32_t lcid, uint32_t newtx, uint32_t retx);
int get_dl_sched(slot_point pdsch_tti, uint32_t cc, dl_sched_res_t& result) override; int run_slot(slot_point pdsch_tti, uint32_t cc, dl_sched_res_t& result) override;
int get_ul_sched(slot_point pusch_tti, uint32_t cc, ul_sched_t& result) override; int get_ul_sched(slot_point pusch_tti, uint32_t cc, ul_sched_t& result) override;
void get_metrics(mac_metrics_t& metrics);
private: private:
void ue_cfg_impl(uint16_t rnti, const ue_cfg_t& cfg); void ue_cfg_impl(uint16_t rnti, const ue_cfg_t& cfg);

@ -34,12 +34,12 @@ namespace sched_nr_impl {
class si_sched class si_sched
{ {
public: public:
explicit si_sched(const bwp_params& bwp_cfg_); explicit si_sched(const bwp_params_t& bwp_cfg_);
void run_slot(bwp_slot_allocator& slot_alloc); void run_slot(bwp_slot_allocator& slot_alloc);
private: private:
const bwp_params* bwp_cfg = nullptr; const bwp_params_t* bwp_cfg = nullptr;
srslog::basic_logger& logger; srslog::basic_logger& logger;
struct sched_si_t { struct sched_si_t {
@ -54,13 +54,13 @@ private:
srsran::bounded_vector<sched_si_t, 10> pending_sis; srsran::bounded_vector<sched_si_t, 10> pending_sis;
}; };
using dl_sched_rar_info_t = sched_nr_interface::dl_sched_rar_info_t; using dl_sched_rar_info_t = sched_nr_interface::rar_info_t;
/// RAR/Msg3 scheduler /// RAR/Msg3 scheduler
class ra_sched class ra_sched
{ {
public: public:
explicit ra_sched(const bwp_params& bwp_cfg_); explicit ra_sched(const bwp_params_t& bwp_cfg_);
/// Addition of detected PRACH into the queue /// Addition of detected PRACH into the queue
int dl_rach_info(const dl_sched_rar_info_t& rar_info); int dl_rach_info(const dl_sched_rar_info_t& rar_info);
@ -82,7 +82,7 @@ private:
alloc_result alloc_result
allocate_pending_rar(bwp_slot_allocator& slot_grid, const pending_rar_t& rar, uint32_t& nof_grants_alloc); allocate_pending_rar(bwp_slot_allocator& slot_grid, const pending_rar_t& rar, uint32_t& nof_grants_alloc);
const bwp_params* bwp_cfg = nullptr; const bwp_params_t* bwp_cfg = nullptr;
srslog::basic_logger& logger; srslog::basic_logger& logger;
srsran::deque<pending_rar_t> pending_rars; srsran::deque<pending_rar_t> pending_rars;
@ -91,9 +91,9 @@ private:
class bwp_ctxt class bwp_ctxt
{ {
public: public:
explicit bwp_ctxt(const bwp_params& bwp_cfg); explicit bwp_ctxt(const bwp_params_t& bwp_cfg);
const bwp_params* cfg; const bwp_params_t* cfg;
// channel-specific schedulers // channel-specific schedulers
ra_sched ra; ra_sched ra;
@ -108,10 +108,10 @@ class serv_cell_manager
public: public:
using feedback_callback_t = srsran::move_callback<void(ue_carrier&)>; using feedback_callback_t = srsran::move_callback<void(ue_carrier&)>;
explicit serv_cell_manager(const sched_cell_params& cell_cfg_); explicit serv_cell_manager(const cell_params_t& cell_cfg_);
srsran::bounded_vector<bwp_ctxt, SCHED_NR_MAX_BWP_PER_CELL> bwps; srsran::bounded_vector<bwp_ctxt, SCHED_NR_MAX_BWP_PER_CELL> bwps;
const sched_cell_params& cfg; const cell_params_t& cfg;
private: private:
srslog::basic_logger& logger; srslog::basic_logger& logger;

@ -35,7 +35,7 @@ static const size_t MAX_NOF_AGGR_LEVELS = 5;
namespace sched_nr_impl { namespace sched_nr_impl {
const static size_t MAX_GRANTS = sched_nr_interface::MAX_GRANTS; constexpr static size_t MAX_GRANTS = sched_nr_interface::MAX_GRANTS;
using pdcch_dl_t = mac_interface_phy_nr::pdcch_dl_t; using pdcch_dl_t = mac_interface_phy_nr::pdcch_dl_t;
using pdcch_ul_t = mac_interface_phy_nr::pdcch_ul_t; using pdcch_ul_t = mac_interface_phy_nr::pdcch_ul_t;
@ -49,13 +49,18 @@ using pusch_list_t = srsran::bounded_vector<pusch_t, MAX_GRANTS>;
using nzp_csi_rs_list = srsran::bounded_vector<srsran_csi_rs_nzp_resource_t, mac_interface_phy_nr::MAX_NZP_CSI_RS>; using nzp_csi_rs_list = srsran::bounded_vector<srsran_csi_rs_nzp_resource_t, mac_interface_phy_nr::MAX_NZP_CSI_RS>;
using ssb_t = mac_interface_phy_nr::ssb_t; using ssb_t = mac_interface_phy_nr::ssb_t;
using ssb_list = srsran::bounded_vector<ssb_t, mac_interface_phy_nr::MAX_SSB>; using ssb_list = srsran::bounded_vector<ssb_t, mac_interface_phy_nr::MAX_SSB>;
using sched_args_t = sched_nr_interface::sched_args_t;
using sched_cfg_t = sched_nr_interface::sched_cfg_t;
using cell_cfg_t = sched_nr_interface::cell_cfg_t; using cell_cfg_t = sched_nr_interface::cell_cfg_t;
using bwp_cfg_t = sched_nr_interface::bwp_cfg_t; using bwp_cfg_t = sched_nr_interface::bwp_cfg_t;
using ue_cfg_t = sched_nr_interface::ue_cfg_t;
using ue_cc_cfg_t = sched_nr_interface::ue_cc_cfg_t;
using pdcch_cce_pos_list = srsran::bounded_vector<uint32_t, SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR>; using pdcch_cce_pos_list = srsran::bounded_vector<uint32_t, SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR>;
using bwp_cce_pos_list = std::array<std::array<pdcch_cce_pos_list, MAX_NOF_AGGR_LEVELS>, SRSRAN_NOF_SF_X_FRAME>; using bwp_cce_pos_list = std::array<std::array<pdcch_cce_pos_list, MAX_NOF_AGGR_LEVELS>, SRSRAN_NOF_SF_X_FRAME>;
using dl_sched_t = sched_nr_interface::dl_sched_t;
using ul_sched_t = sched_nr_interface::ul_sched_t;
using dl_sched_res_t = sched_nr_interface::dl_sched_res_t;
/// Generate list of CCE locations for UE based on coreset and search space configurations
void get_dci_locs(const srsran_coreset_t& coreset, void get_dci_locs(const srsran_coreset_t& coreset,
const srsran_search_space_t& search_space, const srsran_search_space_t& search_space,
uint16_t rnti, uint16_t rnti,
@ -63,18 +68,22 @@ void get_dci_locs(const srsran_coreset_t& coreset,
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct bwp_params { /// Structure that extends the sched_nr_interface::bwp_cfg_t passed by upper layers with other
/// derived BWP-specific params
struct bwp_params_t {
const uint32_t bwp_id; const uint32_t bwp_id;
const uint32_t cc; const uint32_t cc;
const bwp_cfg_t& cfg; const bwp_cfg_t& cfg;
const cell_cfg_t& cell_cfg; const cell_cfg_t& cell_cfg;
const sched_cfg_t& sched_cfg; const sched_args_t& sched_cfg;
// derived params // derived params
srslog::basic_logger& logger; srslog::basic_logger& logger;
uint32_t P; uint32_t P;
uint32_t N_rbg; uint32_t N_rbg;
uint32_t nof_prb() const { return cell_cfg.carrier.nof_prb; }
/// Table specifying if a slot has DL or UL enabled
struct slot_cfg { struct slot_cfg {
bool is_dl; bool is_dl;
bool is_ul; bool is_ul;
@ -91,48 +100,50 @@ struct bwp_params {
bwp_cce_pos_list rar_cce_list; bwp_cce_pos_list rar_cce_list;
bwp_params(const cell_cfg_t& cell, const sched_cfg_t& sched_cfg_, uint32_t cc, uint32_t bwp_id); bwp_params_t(const cell_cfg_t& cell, const sched_args_t& sched_cfg_, uint32_t cc, uint32_t bwp_id);
}; };
struct sched_cell_params { /// Structure packing a single cell config params, and sched args
struct cell_params_t {
const uint32_t cc; const uint32_t cc;
const cell_cfg_t cell_cfg; const cell_cfg_t cfg;
const sched_cfg_t& sched_cfg; const sched_args_t& sched_args;
std::vector<bwp_params> bwps; std::vector<bwp_params_t> bwps;
sched_cell_params(uint32_t cc_, const cell_cfg_t& cell, const sched_cfg_t& sched_cfg_); cell_params_t(uint32_t cc_, const cell_cfg_t& cell, const sched_args_t& sched_cfg_);
uint32_t nof_prb() const { return cell_cfg.carrier.nof_prb; } uint32_t nof_prb() const { return cfg.carrier.nof_prb; }
}; };
/// Structure packing both the sched args and all gNB NR cell configurations
struct sched_params { struct sched_params {
sched_cfg_t sched_cfg; sched_args_t sched_cfg;
std::vector<sched_cell_params> cells; std::vector<cell_params_t> cells;
sched_params() = default; sched_params() = default;
explicit sched_params(const sched_cfg_t& sched_cfg_); explicit sched_params(const sched_args_t& sched_cfg_);
}; };
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
using prb_bitmap = srsran::bounded_bitset<SRSRAN_MAX_PRB_NR, true>; /// Configuration of a UE for a given BWP
using pdcchmask_t = srsran::bounded_bitset<SCHED_NR_MAX_NOF_RBGS, true>;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
using ue_cfg_t = sched_nr_interface::ue_cfg_t;
using ue_cc_cfg_t = sched_nr_interface::ue_cc_cfg_t;
class bwp_ue_cfg class bwp_ue_cfg
{ {
public: public:
bwp_ue_cfg() = default; bwp_ue_cfg() = default;
explicit bwp_ue_cfg(uint16_t rnti, const bwp_params& bwp_cfg, const ue_cfg_t& uecfg_); explicit bwp_ue_cfg(uint16_t rnti, const bwp_params_t& bwp_cfg, const ue_cfg_t& uecfg_);
const ue_cfg_t* ue_cfg() const { return cfg_; } const ue_cfg_t* ue_cfg() const { return cfg_; }
const srsran::phy_cfg_nr_t& phy() const { return cfg_->phy_cfg; } const srsran::phy_cfg_nr_t& phy() const { return cfg_->phy_cfg; }
const bwp_params& active_bwp() const { return *bwp_cfg; } const bwp_params_t& active_bwp() const { return *bwp_cfg; }
srsran::const_span<uint32_t> cce_pos_list(uint32_t search_id, uint32_t slot_idx, uint32_t aggr_idx) const
{
if (cce_positions_list.size() > ss_id_to_cce_idx[search_id]) {
auto& lst = cce_pos_list(search_id);
return lst[slot_idx][aggr_idx];
}
return srsran::const_span<uint32_t>{};
}
const bwp_cce_pos_list& cce_pos_list(uint32_t search_id) const const bwp_cce_pos_list& cce_pos_list(uint32_t search_id) const
{ {
return cce_positions_list[ss_id_to_cce_idx[search_id]]; return cce_positions_list[ss_id_to_cce_idx[search_id]];
@ -144,11 +155,13 @@ public:
} }
return phy().harq_ack.dl_data_to_ul_ack[pdsch_slot.to_uint() % phy().harq_ack.nof_dl_data_to_ul_ack]; return phy().harq_ack.dl_data_to_ul_ack[pdsch_slot.to_uint() % phy().harq_ack.nof_dl_data_to_ul_ack];
} }
int fixed_pdsch_mcs() const { return bwp_cfg->sched_cfg.fixed_dl_mcs; }
int fixed_pusch_mcs() const { return bwp_cfg->sched_cfg.fixed_ul_mcs; }
private: private:
uint16_t rnti = SRSRAN_INVALID_RNTI; uint16_t rnti = SRSRAN_INVALID_RNTI;
const ue_cfg_t* cfg_ = nullptr; const ue_cfg_t* cfg_ = nullptr;
const bwp_params* bwp_cfg = nullptr; const bwp_params_t* bwp_cfg = nullptr;
std::vector<bwp_cce_pos_list> cce_positions_list; std::vector<bwp_cce_pos_list> cce_positions_list;
std::array<uint32_t, SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE> ss_id_to_cce_idx; std::array<uint32_t, SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE> ss_id_to_cce_idx;

@ -33,7 +33,7 @@ namespace srsenb {
namespace sched_nr_impl { namespace sched_nr_impl {
// typedefs // typedefs
using dl_sched_rar_info_t = sched_nr_interface::dl_sched_rar_info_t; using dl_sched_rar_info_t = sched_nr_interface::rar_info_t;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -54,7 +54,7 @@ using harq_ack_list_t = srsran::bounded_vector<harq_ack_t, MAX_GRANTS>;
/// This only contains information about a given slot /// This only contains information about a given slot
struct bwp_slot_grid { struct bwp_slot_grid {
uint32_t slot_idx = 0; uint32_t slot_idx = 0;
const bwp_params* cfg = nullptr; const bwp_params_t* cfg = nullptr;
bwp_rb_bitmap dl_prbs; bwp_rb_bitmap dl_prbs;
bwp_rb_bitmap ul_prbs; bwp_rb_bitmap ul_prbs;
@ -72,7 +72,7 @@ struct bwp_slot_grid {
srsran::unique_pool_ptr<tx_harq_softbuffer> rar_softbuffer; srsran::unique_pool_ptr<tx_harq_softbuffer> rar_softbuffer;
bwp_slot_grid() = default; bwp_slot_grid() = default;
explicit bwp_slot_grid(const bwp_params& bwp_params, uint32_t slot_idx_); explicit bwp_slot_grid(const bwp_params_t& bwp_params, uint32_t slot_idx_);
void reset(); void reset();
bool is_dl() const { return cfg->slots[slot_idx].is_dl; } bool is_dl() const { return cfg->slots[slot_idx].is_dl; }
@ -80,14 +80,14 @@ struct bwp_slot_grid {
}; };
struct bwp_res_grid { struct bwp_res_grid {
explicit bwp_res_grid(const bwp_params& bwp_cfg_); explicit bwp_res_grid(const bwp_params_t& bwp_cfg_);
bwp_slot_grid& operator[](slot_point tti) { return slots[tti.to_uint() % slots.capacity()]; }; bwp_slot_grid& operator[](slot_point tti) { return slots[tti.to_uint() % slots.capacity()]; };
const bwp_slot_grid& operator[](slot_point tti) const { return slots[tti.to_uint() % slots.capacity()]; }; const bwp_slot_grid& operator[](slot_point tti) const { return slots[tti.to_uint() % slots.capacity()]; };
uint32_t id() const { return cfg->bwp_id; } uint32_t id() const { return cfg->bwp_id; }
uint32_t nof_prbs() const { return cfg->cfg.rb_width; } uint32_t nof_prbs() const { return cfg->cfg.rb_width; }
const bwp_params* cfg = nullptr; const bwp_params_t* cfg = nullptr;
private: private:
// TTIMOD_SZ is the longest allocation in the future // TTIMOD_SZ is the longest allocation in the future
@ -123,7 +123,7 @@ public:
slot_point get_tti_rx() const { return pdcch_slot - TX_ENB_DELAY; } slot_point get_tti_rx() const { return pdcch_slot - TX_ENB_DELAY; }
const bwp_res_grid& res_grid() const { return bwp_grid; } const bwp_res_grid& res_grid() const { return bwp_grid; }
const bwp_params& cfg; const bwp_params_t& cfg;
private: private:
alloc_result verify_pdsch_space(bwp_slot_grid& pdsch_grid, bwp_slot_grid& pdcch_grid) const; alloc_result verify_pdsch_space(bwp_slot_grid& pdsch_grid, bwp_slot_grid& pdcch_grid) const;

@ -57,17 +57,13 @@ public:
void new_slot(slot_point slot_rx); void new_slot(slot_point slot_rx);
void reset(); void reset();
bool new_tx(slot_point slot_tx, bool new_tx(slot_point slot_tx, slot_point slot_ack, const prb_grant& grant, uint32_t mcs, uint32_t max_retx);
slot_point slot_ack,
const prb_grant& grant,
uint32_t mcs,
uint32_t tbs,
uint32_t max_retx);
bool new_retx(slot_point slot_tx, slot_point slot_ack, const prb_grant& grant); bool new_retx(slot_point slot_tx, slot_point slot_ack, const prb_grant& grant);
bool new_retx(slot_point slot_tx, slot_point slot_ack); bool new_retx(slot_point slot_tx, slot_point slot_ack);
// NOTE: Has to be used before first tx is dispatched // NOTE: Has to be used before first tx is dispatched
bool set_tbs(uint32_t tbs); bool set_tbs(uint32_t tbs);
bool set_mcs(uint32_t mcs);
const uint32_t pid; const uint32_t pid;
@ -96,12 +92,7 @@ public:
tx_harq_softbuffer& get_softbuffer() { return *softbuffer; } tx_harq_softbuffer& get_softbuffer() { return *softbuffer; }
srsran::unique_byte_buffer_t* get_tx_pdu() { return &pdu; } srsran::unique_byte_buffer_t* get_tx_pdu() { return &pdu; }
bool new_tx(slot_point slot_tx, bool new_tx(slot_point slot_tx, slot_point slot_ack, const prb_grant& grant, uint32_t mcs, uint32_t max_retx);
slot_point slot_ack,
const prb_grant& grant,
uint32_t mcs,
uint32_t tbs,
uint32_t max_retx);
private: private:
srsran::unique_pool_ptr<tx_harq_softbuffer> softbuffer; srsran::unique_pool_ptr<tx_harq_softbuffer> softbuffer;
@ -119,7 +110,7 @@ public:
bool set_tbs(uint32_t tbs) bool set_tbs(uint32_t tbs)
{ {
softbuffer->reset(tbs * 8u); softbuffer->reset(tbs);
return harq_proc::set_tbs(tbs); return harq_proc::set_tbs(tbs);
} }

@ -34,20 +34,20 @@ struct bwp_res_grid;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool fill_dci_rar(prb_interval interv, uint16_t ra_rnti, const bwp_params& bwp_cfg, srsran_dci_dl_nr_t& dci); bool fill_dci_rar(prb_interval interv, uint16_t ra_rnti, const bwp_params_t& bwp_cfg, srsran_dci_dl_nr_t& dci);
bool fill_dci_msg3(const slot_ue& ue, const bwp_params& bwp_cfg, srsran_dci_ul_nr_t& dci); bool fill_dci_msg3(const slot_ue& ue, const bwp_params_t& bwp_cfg, srsran_dci_ul_nr_t& dci);
/// Generate PDCCH DL DCI fields /// Generate PDCCH DL DCI fields
void fill_dl_dci_ue_fields(const slot_ue& ue, void fill_dl_dci_ue_fields(const slot_ue& ue,
const bwp_params& bwp_cfg, const bwp_params_t& bwp_cfg,
uint32_t ss_id, uint32_t ss_id,
srsran_dci_location_t dci_pos, srsran_dci_location_t dci_pos,
srsran_dci_dl_nr_t& dci); srsran_dci_dl_nr_t& dci);
/// Generate PDCCH UL DCI fields /// Generate PDCCH UL DCI fields
void fill_ul_dci_ue_fields(const slot_ue& ue, void fill_ul_dci_ue_fields(const slot_ue& ue,
const bwp_params& bwp_cfg, const bwp_params_t& bwp_cfg,
uint32_t ss_id, uint32_t ss_id,
srsran_dci_location_t dci_pos, srsran_dci_location_t dci_pos,
srsran_dci_ul_nr_t& dci); srsran_dci_ul_nr_t& dci);

@ -37,11 +37,23 @@ const static size_t SCHED_NR_MAX_CARRIERS = 4;
const static uint16_t SCHED_NR_INVALID_RNTI = 0; const static uint16_t SCHED_NR_INVALID_RNTI = 0;
const static size_t SCHED_NR_MAX_NOF_RBGS = 18; const static size_t SCHED_NR_MAX_NOF_RBGS = 18;
const static size_t SCHED_NR_MAX_TB = 1; const static size_t SCHED_NR_MAX_TB = 1;
const static size_t SCHED_NR_MAX_HARQ = 16; const static size_t SCHED_NR_MAX_HARQ = SRSRAN_DEFAULT_HARQ_PROC_DL_NR;
const static size_t SCHED_NR_MAX_BWP_PER_CELL = 2; const static size_t SCHED_NR_MAX_BWP_PER_CELL = 2;
const static size_t SCHED_NR_MAX_LCID = 32; const static size_t SCHED_NR_MAX_LCID = 32;
const static size_t SCHED_NR_MAX_LC_GROUP = 7; const static size_t SCHED_NR_MAX_LC_GROUP = 7;
struct sched_nr_ue_cc_cfg_t {
bool active = false;
uint32_t cc = 0;
};
struct sched_nr_ue_cfg_t {
uint32_t maxharq_tx = 4;
srsran::bounded_vector<sched_nr_ue_cc_cfg_t, SCHED_NR_MAX_CARRIERS> carriers;
std::array<mac_lc_ch_cfg_t, SCHED_NR_MAX_LCID> ue_bearers = {};
srsran::phy_cfg_nr_t phy_cfg = {};
};
class sched_nr_interface class sched_nr_interface
{ {
public: public:
@ -76,30 +88,21 @@ public:
srsran::bounded_vector<bwp_cfg_t, SCHED_NR_MAX_BWP_PER_CELL> bwps{1}; // idx0 for BWP-common srsran::bounded_vector<bwp_cfg_t, SCHED_NR_MAX_BWP_PER_CELL> bwps{1}; // idx0 for BWP-common
}; };
struct sched_cfg_t { struct sched_args_t {
bool pdsch_enabled = true; bool pdsch_enabled = true;
bool pusch_enabled = true; bool pusch_enabled = true;
bool auto_refill_buffer = false; bool auto_refill_buffer = false;
int fixed_dl_mcs = 28;
int fixed_ul_mcs = 28;
std::string logger_name = "MAC-NR"; std::string logger_name = "MAC-NR";
}; };
struct ue_cc_cfg_t { using ue_cc_cfg_t = sched_nr_ue_cc_cfg_t;
bool active = false; using ue_cfg_t = sched_nr_ue_cfg_t;
uint32_t cc = 0;
};
struct ue_cfg_t { ////// RA procedure //////
uint32_t maxharq_tx = 4;
int fixed_dl_mcs = -1;
int fixed_ul_mcs = -1;
srsran::bounded_vector<ue_cc_cfg_t, SCHED_NR_MAX_CARRIERS> carriers;
std::array<mac_lc_ch_cfg_t, SCHED_NR_MAX_LCID> ue_bearers = {};
srsran::phy_cfg_nr_t phy_cfg = {};
};
////// RACH //////
struct dl_sched_rar_info_t { struct rar_info_t {
uint32_t preamble_idx; // is this the RAPID? uint32_t preamble_idx; // is this the RAPID?
uint32_t ofdm_symbol_idx; uint32_t ofdm_symbol_idx;
uint32_t freq_idx; uint32_t freq_idx;
@ -108,31 +111,31 @@ public:
uint32_t msg3_size = 7; uint32_t msg3_size = 7;
slot_point prach_slot; slot_point prach_slot;
}; };
struct msg3_grant_t {
rar_info_t data;
srsran_dci_ul_nr_t msg3_dci = {};
};
struct rar_t {
srsran::bounded_vector<msg3_grant_t, MAX_GRANTS> grants;
};
///// Sched Result ///// ///// Sched Result /////
using dl_sched_t = mac_interface_phy_nr::dl_sched_t; using dl_sched_t = mac_interface_phy_nr::dl_sched_t;
using ul_sched_t = mac_interface_phy_nr::ul_sched_t; using ul_sched_t = mac_interface_phy_nr::ul_sched_t;
struct sched_rar_grant_t { using sched_rar_list_t = srsran::bounded_vector<rar_t, MAX_GRANTS>;
dl_sched_rar_info_t data;
srsran_dci_ul_nr_t msg3_dci = {};
};
struct sched_rar_t {
srsran::bounded_vector<sched_rar_grant_t, MAX_GRANTS> grants;
};
using sched_rar_list_t = srsran::bounded_vector<sched_rar_t, MAX_GRANTS>;
struct dl_sched_res_t { struct dl_sched_res_t {
sched_rar_list_t rar; sched_rar_list_t rar;
dl_sched_t dl_sched; dl_sched_t dl_sched;
}; };
virtual ~sched_nr_interface() = default; virtual ~sched_nr_interface() = default;
virtual int config(const sched_cfg_t& sched_cfg, srsran::const_span<sched_nr_interface::cell_cfg_t> ue_cfg) = 0; virtual int config(const sched_args_t& sched_cfg, srsran::const_span<sched_nr_interface::cell_cfg_t> ue_cfg) = 0;
virtual void ue_cfg(uint16_t rnti, const ue_cfg_t& ue_cfg) = 0; virtual void ue_cfg(uint16_t rnti, const ue_cfg_t& ue_cfg) = 0;
virtual void ue_rem(uint16_t rnti) = 0; virtual void ue_rem(uint16_t rnti) = 0;
virtual bool ue_exists(uint16_t rnti) = 0; virtual bool ue_exists(uint16_t rnti) = 0;
virtual int get_dl_sched(slot_point slot_rx, uint32_t cc, dl_sched_res_t& result) = 0; virtual int run_slot(slot_point slot_rx, uint32_t cc, dl_sched_res_t& result) = 0;
virtual int get_ul_sched(slot_point slot_rx, uint32_t cc, ul_sched_t& result) = 0; virtual int get_ul_sched(slot_point slot_rx, uint32_t cc, ul_sched_t& result) = 0;
virtual void dl_ack_info(uint16_t rnti, uint32_t cc, uint32_t pid, uint32_t tb_idx, bool ack) = 0; virtual void dl_ack_info(uint16_t rnti, uint32_t cc, uint32_t pid, uint32_t tb_idx, bool ack) = 0;

@ -43,7 +43,7 @@ using bwp_cfg_t = sched_nr_interface::bwp_cfg_t;
class coreset_region class coreset_region
{ {
public: public:
coreset_region(const bwp_params& bwp_cfg_, coreset_region(const bwp_params_t& bwp_cfg_,
uint32_t coreset_id_, uint32_t coreset_id_,
uint32_t slot_idx, uint32_t slot_idx,
pdcch_dl_list_t& pdcch_dl_list, pdcch_dl_list_t& pdcch_dl_list,

@ -51,7 +51,7 @@ void sched_nzp_csi_rs(srsran::const_span<srsran_csi_rs_nzp_set_t> nzp_csi_rs_set
void sched_ssb_basic(const slot_point& sl_point, uint32_t ssb_periodicity, ssb_list& ssb_list); void sched_ssb_basic(const slot_point& sl_point, uint32_t ssb_periodicity, ssb_list& ssb_list);
/// For a given BWP and slot, schedule SSB, NZP CSI RS and SIBs /// For a given BWP and slot, schedule SSB, NZP CSI RS and SIBs
void sched_dl_signalling(const bwp_params& bwp_params, void sched_dl_signalling(const bwp_params_t& bwp_params,
slot_point sl_pdcch, slot_point sl_pdcch,
ssb_list& ssb_list, ssb_list& ssb_list,
nzp_csi_rs_list& nzp_csi_rs); nzp_csi_rs_list& nzp_csi_rs);

@ -25,6 +25,7 @@
#include "sched_nr_cfg.h" #include "sched_nr_cfg.h"
#include "sched_nr_harq.h" #include "sched_nr_harq.h"
#include "sched_nr_interface.h" #include "sched_nr_interface.h"
#include "srsenb/hdr/stack/mac/common/mac_metrics.h"
#include "srsenb/hdr/stack/mac/common/ue_buffer_manager.h" #include "srsenb/hdr/stack/mac/common/ue_buffer_manager.h"
#include "srsran/adt/circular_map.h" #include "srsran/adt/circular_map.h"
#include "srsran/adt/move_callback.h" #include "srsran/adt/move_callback.h"
@ -70,8 +71,9 @@ public:
class ue_carrier class ue_carrier
{ {
public: public:
ue_carrier(uint16_t rnti, const ue_cfg_t& cfg, const sched_cell_params& cell_params_); ue_carrier(uint16_t rnti, const ue_cfg_t& cfg, const cell_params_t& cell_params_);
slot_ue try_reserve(slot_point pdcch_slot, const ue_cfg_t& uecfg_, uint32_t dl_harq_bytes, uint32_t ul_harq_bytes); void set_cfg(const ue_cfg_t& ue_cfg);
slot_ue try_reserve(slot_point pdcch_slot, uint32_t dl_harq_bytes, uint32_t ul_harq_bytes);
const uint16_t rnti; const uint16_t rnti;
const uint32_t cc; const uint32_t cc;
@ -82,9 +84,13 @@ public:
harq_entity harq_ent; harq_entity harq_ent;
// metrics
mac_ue_metrics_t metrics = {};
std::mutex metrics_mutex;
private: private:
bwp_ue_cfg bwp_cfg; bwp_ue_cfg bwp_cfg;
const sched_cell_params& cell_params; const cell_params_t& cell_params;
}; };
class ue class ue

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save