SRSUE/SRSENB: Refactor NR workers to generalise lower PHY

master
Xavier Arteaga 4 years ago committed by Xavier Arteaga
parent 83bf5dcd49
commit 027201d457

@ -0,0 +1,29 @@
/**
*
* \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_PHY_COMMON_INTERFACE_H
#define SRSRAN_PHY_COMMON_INTERFACE_H
#include "../radio/rf_buffer.h"
#include "../radio/rf_timestamp.h"
namespace srsran {
class phy_common_interface
{
public:
virtual void worker_end(void* h, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) = 0;
};
} // namespace srsran
#endif // SRSRAN_PHY_COMMON_INTERFACE_H

@ -13,6 +13,7 @@
#ifndef SRSENB_NR_CC_WORKER_H
#define SRSENB_NR_CC_WORKER_H
#include "srsenb/hdr/phy/phy_interfaces.h"
#include "srsran/interfaces/gnb_interfaces.h"
#include "srsran/interfaces/rrc_nr_interface_types.h"
#include "srsran/phy/enb/enb_dl_nr.h"
@ -24,16 +25,18 @@
namespace srsenb {
namespace nr {
typedef struct {
uint32_t nof_carriers;
srsran_enb_dl_nr_args_t dl;
} phy_nr_args_t;
struct phy_nr_args_t {
uint32_t nof_carriers = 1;
uint32_t nof_ports = 1;
srsran_enb_dl_nr_args_t dl = {};
};
class phy_nr_state
{
public:
phy_nr_args_t args = {};
srsran::phy_cfg_nr_t cfg = {};
phy_cell_cfg_list_nr_t cell_list = {};
phy_nr_args_t args;
srsran::phy_cfg_nr_t cfg;
phy_nr_state()
{
@ -49,7 +52,7 @@ public:
class cc_worker
{
public:
cc_worker(uint32_t cc_idx, srslog::basic_logger& logger, phy_nr_state* phy_state_);
cc_worker(uint32_t cc_idx, srslog::basic_logger& logger, phy_nr_state& phy_state_);
~cc_worker();
bool set_carrier(const srsran_carrier_nr_t* carrier);
@ -70,7 +73,7 @@ private:
std::array<cf_t*, SRSRAN_MAX_PORTS> tx_buffer = {};
std::array<cf_t*, SRSRAN_MAX_PORTS> rx_buffer = {};
uint32_t buffer_sz = 0;
phy_nr_state* phy_state;
phy_nr_state& phy_state;
srsran_enb_dl_nr_t enb_dl = {};
srslog::basic_logger& logger;
};

@ -10,12 +10,12 @@
*
*/
#ifndef SRSUE_NR_PHCH_WORKER_H
#define SRSUE_NR_PHCH_WORKER_H
#ifndef SRSENB_NR_PHCH_WORKER_H
#define SRSENB_NR_PHCH_WORKER_H
#include "cc_worker.h"
#include "srsenb/hdr/phy/phy_common.h"
#include "srsran/common/thread_pool.h"
#include "srsran/interfaces/phy_common_interface.h"
#include "srsran/srslog/srslog.h"
namespace srsenb {
@ -32,7 +32,7 @@ namespace nr {
class sf_worker final : public srsran::thread_pool::worker
{
public:
sf_worker(phy_common* phy_, phy_nr_state* phy_state_, srslog::basic_logger& logger);
sf_worker(srsran::phy_common_interface& common_, phy_nr_state& phy_state_, srslog::basic_logger& logger);
~sf_worker();
bool set_carrier_unlocked(uint32_t cc_idx, const srsran_carrier_nr_t* carrier_);
@ -49,9 +49,9 @@ private:
std::vector<std::unique_ptr<cc_worker> > cc_workers;
phy_common* phy = nullptr;
phy_nr_state* phy_state = nullptr;
srslog::basic_logger& logger;
srsran::phy_common_interface& common;
phy_nr_state& phy_state;
srslog::basic_logger& logger;
// Temporal attributes
srsran_softbuffer_tx_t softbuffer_tx = {};
@ -61,4 +61,4 @@ private:
} // namespace nr
} // namespace srsenb
#endif // SRSUE_NR_PHCH_WORKER_H
#endif // SRSENB_NR_PHCH_WORKER_H

@ -10,10 +10,11 @@
*
*/
#ifndef SRSUE_NR_WORKER_POOL_H
#define SRSUE_NR_WORKER_POOL_H
#ifndef SRSENB_NR_WORKER_POOL_H
#define SRSENB_NR_WORKER_POOL_H
#include "sf_worker.h"
#include "srsenb/hdr/phy/phy_interfaces.h"
#include "srsran/common/thread_pool.h"
namespace srsenb {
@ -29,7 +30,11 @@ public:
sf_worker* operator[](std::size_t pos) { return workers.at(pos).get(); }
worker_pool(uint32_t max_workers);
bool init(const phy_args_t& args, phy_common* common, srslog::sink& log_sink, int prio);
bool init(const phy_cell_cfg_list_nr_t& cell_list,
const phy_args_t& args,
srsran::phy_common_interface& common,
srslog::sink& log_sink,
int prio);
sf_worker* wait_worker(uint32_t tti);
sf_worker* wait_worker_id(uint32_t id);
void start_worker(sf_worker* w);
@ -39,4 +44,4 @@ public:
} // namespace nr
} // namespace srsenb
#endif // SRSUE_NR_WORKER_POOL_H
#endif // SRSENB_NR_WORKER_POOL_H

@ -21,6 +21,7 @@
#include "srsran/common/thread_pool.h"
#include "srsran/common/threads.h"
#include "srsran/interfaces/enb_metrics_interface.h"
#include "srsran/interfaces/phy_common_interface.h"
#include "srsran/interfaces/radio_interfaces.h"
#include "srsran/phy/channel/channel.h"
#include "srsran/radio/radio.h"
@ -31,7 +32,7 @@
namespace srsenb {
class phy_common
class phy_common : public srsran::phy_common_interface
{
public:
phy_common() = default;
@ -56,7 +57,10 @@ public:
* @param tx_time timestamp to transmit samples
* @param is_nr flag is true if it is called from NR
*/
void worker_end(void* tx_sem_id, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr = false);
void worker_end(void* tx_sem_id,
srsran::rf_buffer_t& buffer,
srsran::rf_timestamp_t& tx_time,
bool is_nr = false) override;
// Common objects
phy_args_t params = {};
@ -151,15 +155,6 @@ public:
}
return c;
};
srsran_carrier_nr_t get_cell_nr(uint32_t cc_idx)
{
srsran_carrier_nr_t c = {};
if (cc_idx < cell_list_nr.size()) {
c = cell_list_nr[cc_idx].carrier;
}
return c;
};
void set_cell_gain(uint32_t cell_id, float gain_db)
{

@ -15,20 +15,20 @@
namespace srsenb {
namespace nr {
cc_worker::cc_worker(uint32_t cc_idx_, srslog::basic_logger& log, phy_nr_state* phy_state_) :
cc_worker::cc_worker(uint32_t cc_idx_, srslog::basic_logger& log, phy_nr_state& phy_state_) :
cc_idx(cc_idx_), phy_state(phy_state_), logger(log)
{
cf_t* buffer_c[SRSRAN_MAX_PORTS] = {};
// Allocate buffers
buffer_sz = SRSRAN_SF_LEN_PRB(phy_state->args.dl.nof_max_prb);
for (uint32_t i = 0; i < phy_state_->args.dl.nof_tx_antennas; i++) {
buffer_sz = SRSRAN_SF_LEN_PRB(phy_state.args.dl.nof_max_prb);
for (uint32_t i = 0; i < phy_state.args.dl.nof_tx_antennas; i++) {
tx_buffer[i] = srsran_vec_cf_malloc(buffer_sz);
rx_buffer[i] = srsran_vec_cf_malloc(buffer_sz);
buffer_c[i] = tx_buffer[i];
}
if (srsran_enb_dl_nr_init(&enb_dl, buffer_c, &phy_state_->args.dl)) {
if (srsran_enb_dl_nr_init(&enb_dl, buffer_c, &phy_state.args.dl)) {
ERROR("Error initiating UE DL NR");
return;
}
@ -60,8 +60,8 @@ bool cc_worker::set_carrier(const srsran_carrier_nr_t* carrier)
coreset.freq_resources[0] = true; // Enable the bottom 6 PRB for PDCCH
coreset.duration = 2;
srsran_dci_cfg_nr_t dci_cfg = phy_state->cfg.get_dci_cfg();
if (srsran_enb_dl_nr_set_pdcch_config(&enb_dl, &phy_state->cfg.pdcch, &dci_cfg) < SRSRAN_SUCCESS) {
srsran_dci_cfg_nr_t dci_cfg = phy_state.cfg.get_dci_cfg();
if (srsran_enb_dl_nr_set_pdcch_config(&enb_dl, &phy_state.cfg.pdcch, &dci_cfg) < SRSRAN_SUCCESS) {
ERROR("Error setting coreset");
return false;
}
@ -76,7 +76,7 @@ void cc_worker::set_tti(uint32_t tti)
cf_t* cc_worker::get_tx_buffer(uint32_t antenna_idx)
{
if (antenna_idx >= phy_state->args.dl.nof_tx_antennas) {
if (antenna_idx >= phy_state.args.dl.nof_tx_antennas) {
return nullptr;
}
@ -85,7 +85,7 @@ cf_t* cc_worker::get_tx_buffer(uint32_t antenna_idx)
cf_t* cc_worker::get_rx_buffer(uint32_t antenna_idx)
{
if (antenna_idx >= phy_state->args.dl.nof_tx_antennas) {
if (antenna_idx >= phy_state.args.dl.nof_tx_antennas) {
return nullptr;
}

@ -14,10 +14,10 @@
namespace srsenb {
namespace nr {
sf_worker::sf_worker(phy_common* phy_, phy_nr_state* phy_state_, srslog::basic_logger& logger) :
phy(phy_), phy_state(phy_state_), logger(logger)
sf_worker::sf_worker(srsran::phy_common_interface& common_, phy_nr_state& phy_state_, srslog::basic_logger& logger) :
common(common_), phy_state(phy_state_), logger(logger)
{
for (uint32_t i = 0; i < phy_state->args.nof_carriers; i++) {
for (uint32_t i = 0; i < phy_state.args.nof_carriers; i++) {
cc_worker* w = new cc_worker(i, logger, phy_state);
cc_workers.push_back(std::unique_ptr<cc_worker>(w));
}
@ -82,14 +82,14 @@ void sf_worker::work_imp()
// Get Transmission buffers
srsran::rf_buffer_t tx_buffer = {};
srsran::rf_timestamp_t dummy_ts = {};
for (uint32_t cc = 0; cc < phy->get_nof_carriers_nr(); cc++) {
for (uint32_t ant = 0; ant < phy->get_nof_ports(0); ant++) {
tx_buffer.set(cc, ant, phy->get_nof_ports(0), cc_workers[cc]->get_tx_buffer(ant));
for (uint32_t cc = 0; cc < phy_state.args.nof_carriers; cc++) {
for (uint32_t ant = 0; ant < phy_state.args.nof_ports; ant++) {
tx_buffer.set(cc, ant, phy_state.args.nof_ports, cc_workers[cc]->get_tx_buffer(ant));
}
}
// Configure user
phy_state->cfg.pdsch.rbg_size_cfg_1 = false;
phy_state.cfg.pdsch.rbg_size_cfg_1 = false;
// Fill grant (this comes from the scheduler)
srsran_slot_cfg_t dl_cfg = {};
@ -116,7 +116,7 @@ void sf_worker::work_imp()
w->work_dl(dl_cfg, grants);
}
phy->worker_end(this, tx_buffer, dummy_ts, true);
common.worker_end(this, tx_buffer, dummy_ts, true);
}
} // namespace nr

@ -16,8 +16,15 @@ namespace nr {
worker_pool::worker_pool(uint32_t max_workers) : pool(max_workers) {}
bool worker_pool::init(const phy_args_t& args, phy_common* common, srslog::sink& log_sink, int prio)
bool worker_pool::init(const phy_cell_cfg_list_nr_t& cell_list,
const phy_args_t& args,
srsran::phy_common_interface& common,
srslog::sink& log_sink,
int prio)
{
// Save cell list
phy_state.cell_list = cell_list;
// Add workers to workers pool and start threads
srslog::basic_levels log_level = srslog::str_to_basic_level(args.log.phy_level);
for (uint32_t i = 0; i < args.nof_phy_threads; i++) {
@ -25,11 +32,11 @@ bool worker_pool::init(const phy_args_t& args, phy_common* common, srslog::sink&
log.set_level(log_level);
log.set_hex_dump_max_size(args.log.phy_hex_limit);
auto w = new sf_worker(common, &phy_state, log);
auto w = new sf_worker(common, phy_state, log);
pool.init_worker(i, w, prio);
workers.push_back(std::unique_ptr<sf_worker>(w));
srsran_carrier_nr_t c = common->get_cell_nr(0);
srsran_carrier_nr_t c = phy_state.cell_list[0].carrier;
w->set_carrier_unlocked(0, &c);
}

@ -132,7 +132,7 @@ int phy::init(const phy_args_t& args,
lte_workers.init(args, &workers_common, log_sink, WORKERS_THREAD_PRIO);
}
if (not cfg.phy_cell_cfg_nr.empty()) {
nr_workers.init(args, &workers_common, log_sink, WORKERS_THREAD_PRIO);
nr_workers.init(cfg.phy_cell_cfg_nr, args, workers_common, log_sink, WORKERS_THREAD_PRIO);
}
// For each carrier, initialise PRACH worker

@ -22,7 +22,7 @@ namespace nr {
class cc_worker
{
public:
cc_worker(uint32_t cc_idx, srslog::basic_logger& log, state* phy_state_);
cc_worker(uint32_t cc_idx, srslog::basic_logger& log, state& phy_state_);
~cc_worker();
bool update_cfg();
@ -49,10 +49,10 @@ private:
std::array<cf_t*, SRSRAN_MAX_PORTS> rx_buffer = {};
std::array<cf_t*, SRSRAN_MAX_PORTS> tx_buffer = {};
uint32_t buffer_sz = 0;
state* phy = nullptr;
srsran_ssb_t ssb = {};
srsran_ue_dl_nr_t ue_dl = {};
srsran_ue_ul_nr_t ue_ul = {};
state& phy;
srsran_ssb_t ssb = {};
srsran_ue_dl_nr_t ue_dl = {};
srsran_ue_ul_nr_t ue_ul = {};
srslog::basic_logger& logger;
// Methods for DCI blind search

@ -13,9 +13,9 @@
#ifndef SRSUE_NR_PHCH_WORKER_H
#define SRSUE_NR_PHCH_WORKER_H
#include "../phy_common.h"
#include "cc_worker.h"
#include "srsran/common/thread_pool.h"
#include "srsran/interfaces/phy_common_interface.h"
namespace srsue {
namespace nr {
@ -31,7 +31,7 @@ namespace nr {
class sf_worker final : public srsran::thread_pool::worker
{
public:
sf_worker(phy_common* phy, state* phy_state_, srslog::basic_logger& logger);
sf_worker(srsran::phy_common_interface& common_, state& phy_state_, srslog::basic_logger& logger);
~sf_worker() = default;
bool update_cfg(uint32_t cc_idx);
@ -51,9 +51,9 @@ private:
std::vector<std::unique_ptr<cc_worker> > cc_workers;
phy_common* phy = nullptr;
state* phy_state = nullptr;
srslog::basic_logger& logger;
srsran::phy_common_interface& common;
state& phy_state;
srslog::basic_logger& logger;
uint32_t tti_rx = 0;
cf_t* prach_ptr = nullptr;

@ -33,7 +33,7 @@ public:
sf_worker* operator[](std::size_t pos) { return workers.at(pos).get(); }
worker_pool(uint32_t max_workers);
bool init(const phy_args_nr_t& args_, phy_common* common, stack_interface_phy_nr* stack_, int prio);
bool init(const phy_args_nr_t& args_, srsran::phy_common_interface& common, stack_interface_phy_nr* stack_, int prio);
sf_worker* wait_worker(uint32_t tti);
void start_worker(sf_worker* w);
void stop();

@ -17,6 +17,7 @@
#include "srsran/adt/circular_array.h"
#include "srsran/common/gen_mch_tables.h"
#include "srsran/common/tti_sempahore.h"
#include "srsran/interfaces/phy_common_interface.h"
#include "srsran/interfaces/phy_interface_types.h"
#include "srsran/interfaces/radio_interfaces.h"
#include "srsran/interfaces/rrc_interface_types.h"
@ -46,7 +47,7 @@ public:
};
/* Subclass that manages variables common to all workers */
class phy_common
class phy_common : public srsran::phy_common_interface
{
public:
/* Common variables used by all phy workers */
@ -129,7 +130,7 @@ public:
srsran_pdsch_ack_resource_t resource);
bool get_dl_pending_ack(srsran_ul_sf_cfg_t* sf, uint32_t cc_idx, srsran_pdsch_ack_cc_t* ack);
void worker_end(void* h, bool tx_enable, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr);
void worker_end(void* h, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) override;
void set_cell(const srsran_cell_t& c);

@ -155,7 +155,7 @@ void sf_worker::work_imp()
{
srsran::rf_buffer_t tx_signal_ptr = {};
if (!cell_initiated) {
phy->worker_end(this, false, tx_signal_ptr, tx_time, false);
phy->worker_end(this, tx_signal_ptr, tx_time, false);
return;
}
@ -216,7 +216,6 @@ void sf_worker::work_imp()
}
}
}
tx_signal_ptr.set_nof_samples(nof_samples);
// Set PRACH buffer signal pointer
if (prach_ptr) {
@ -225,8 +224,13 @@ void sf_worker::work_imp()
prach_ptr = nullptr;
}
// Indicates worker there is a transmission by setting the number of samples
if (tx_signal_ready) {
tx_signal_ptr.set_nof_samples(nof_samples);
}
// Call worker_end to transmit the signal
phy->worker_end(this, tx_signal_ready, tx_signal_ptr, tx_time, false);
phy->worker_end(this, tx_signal_ptr, tx_time, false);
if (rx_signal_ok) {
update_measurements();

@ -17,25 +17,25 @@
namespace srsue {
namespace nr {
cc_worker::cc_worker(uint32_t cc_idx_, srslog::basic_logger& log, state* phy_state_) :
cc_worker::cc_worker(uint32_t cc_idx_, srslog::basic_logger& log, state& phy_state_) :
cc_idx(cc_idx_), phy(phy_state_), logger(log)
{
cf_t* rx_buffer_c[SRSRAN_MAX_PORTS] = {};
// Allocate buffers
buffer_sz = SRSRAN_SF_LEN_PRB(phy->args.dl.nof_max_prb) * 5;
for (uint32_t i = 0; i < phy_state_->args.dl.nof_rx_antennas; i++) {
buffer_sz = SRSRAN_SF_LEN_PRB(phy.args.dl.nof_max_prb) * 5;
for (uint32_t i = 0; i < phy.args.dl.nof_rx_antennas; i++) {
rx_buffer[i] = srsran_vec_cf_malloc(buffer_sz);
rx_buffer_c[i] = rx_buffer[i];
tx_buffer[i] = srsran_vec_cf_malloc(buffer_sz);
}
if (srsran_ue_dl_nr_init(&ue_dl, rx_buffer.data(), &phy_state_->args.dl) < SRSRAN_SUCCESS) {
if (srsran_ue_dl_nr_init(&ue_dl, rx_buffer.data(), &phy.args.dl) < SRSRAN_SUCCESS) {
ERROR("Error initiating UE DL NR");
return;
}
if (srsran_ue_ul_nr_init(&ue_ul, tx_buffer[0], &phy_state_->args.ul) < SRSRAN_SUCCESS) {
if (srsran_ue_ul_nr_init(&ue_ul, tx_buffer[0], &phy.args.ul) < SRSRAN_SUCCESS) {
ERROR("Error initiating UE DL NR");
return;
}
@ -67,38 +67,38 @@ cc_worker::~cc_worker()
bool cc_worker::update_cfg()
{
if (srsran_ue_dl_nr_set_carrier(&ue_dl, &phy->cfg.carrier) < SRSRAN_SUCCESS) {
if (srsran_ue_dl_nr_set_carrier(&ue_dl, &phy.cfg.carrier) < SRSRAN_SUCCESS) {
ERROR("Error setting carrier");
return false;
}
if (srsran_ue_ul_nr_set_carrier(&ue_ul, &phy->cfg.carrier) < SRSRAN_SUCCESS) {
if (srsran_ue_ul_nr_set_carrier(&ue_ul, &phy.cfg.carrier) < SRSRAN_SUCCESS) {
ERROR("Error setting carrier");
return false;
}
srsran_dci_cfg_nr_t dci_cfg = phy->cfg.get_dci_cfg();
if (srsran_ue_dl_nr_set_pdcch_config(&ue_dl, &phy->cfg.pdcch, &dci_cfg) < SRSRAN_SUCCESS) {
srsran_dci_cfg_nr_t dci_cfg = phy.cfg.get_dci_cfg();
if (srsran_ue_dl_nr_set_pdcch_config(&ue_dl, &phy.cfg.pdcch, &dci_cfg) < SRSRAN_SUCCESS) {
logger.error("Error setting NR PDCCH configuration");
return false;
}
double abs_freq_point_a_freq =
srsran::srsran_band_helper().nr_arfcn_to_freq(phy->cfg.carrier.absolute_frequency_point_a);
double abs_freq_ssb_freq = srsran::srsran_band_helper().nr_arfcn_to_freq(phy->cfg.carrier.absolute_frequency_ssb);
srsran::srsran_band_helper().nr_arfcn_to_freq(phy.cfg.carrier.absolute_frequency_point_a);
double abs_freq_ssb_freq = srsran::srsran_band_helper().nr_arfcn_to_freq(phy.cfg.carrier.absolute_frequency_ssb);
double carrier_center_freq = abs_freq_point_a_freq + (phy->cfg.carrier.nof_prb / 2 *
SRSRAN_SUBC_SPACING_NR(phy->cfg.carrier.scs) * SRSRAN_NRE);
uint16_t band = srsran::srsran_band_helper().get_band_from_dl_freq_Hz(carrier_center_freq);
double carrier_center_freq =
abs_freq_point_a_freq + (phy.cfg.carrier.nof_prb / 2 * SRSRAN_SUBC_SPACING_NR(phy.cfg.carrier.scs) * SRSRAN_NRE);
uint16_t band = srsran::srsran_band_helper().get_band_from_dl_freq_Hz(carrier_center_freq);
srsran_ssb_cfg_t ssb_cfg = {};
ssb_cfg.srate_hz = srsran_min_symbol_sz_rb(phy->cfg.carrier.nof_prb) * SRSRAN_SUBC_SPACING_NR(phy->cfg.carrier.scs);
ssb_cfg.srate_hz = srsran_min_symbol_sz_rb(phy.cfg.carrier.nof_prb) * SRSRAN_SUBC_SPACING_NR(phy.cfg.carrier.scs);
ssb_cfg.center_freq_hz = carrier_center_freq;
ssb_cfg.ssb_freq_hz = abs_freq_ssb_freq;
ssb_cfg.scs = phy->cfg.ssb.scs;
ssb_cfg.pattern = srsran::srsran_band_helper().get_ssb_pattern(band, phy->cfg.ssb.scs);
ssb_cfg.scs = phy.cfg.ssb.scs;
ssb_cfg.pattern = srsran::srsran_band_helper().get_ssb_pattern(band, phy.cfg.ssb.scs);
ssb_cfg.duplex_mode = srsran::srsran_band_helper().get_duplex_mode(band);
ssb_cfg.periodicity_ms = phy->cfg.ssb.periodicity_ms;
ssb_cfg.periodicity_ms = phy.cfg.ssb.periodicity_ms;
if (srsran_ssb_set_cfg(&ssb, &ssb_cfg) < SRSRAN_SUCCESS) {
logger.error("Error setting SSB configuration");
@ -119,7 +119,7 @@ void cc_worker::set_tti(uint32_t tti)
cf_t* cc_worker::get_rx_buffer(uint32_t antenna_idx)
{
if (antenna_idx >= phy->args.dl.nof_rx_antennas) {
if (antenna_idx >= phy.args.dl.nof_rx_antennas) {
return nullptr;
}
@ -128,7 +128,7 @@ cf_t* cc_worker::get_rx_buffer(uint32_t antenna_idx)
cf_t* cc_worker::get_tx_buffer(uint32_t antenna_idx)
{
if (antenna_idx >= phy->args.dl.nof_rx_antennas) {
if (antenna_idx >= phy.args.dl.nof_rx_antennas) {
return nullptr;
}
@ -143,7 +143,7 @@ uint32_t cc_worker::get_buffer_len()
void cc_worker::decode_pdcch_dl()
{
std::array<srsran_dci_dl_nr_t, SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR> dci_rx = {};
srsue::mac_interface_phy_nr::sched_rnti_t rnti = phy->stack->get_dl_sched_rnti_nr(dl_slot_cfg.idx);
srsue::mac_interface_phy_nr::sched_rnti_t rnti = phy.stack->get_dl_sched_rnti_nr(dl_slot_cfg.idx);
// Skip search if no valid RNTI is given
if (rnti.id == SRSRAN_INVALID_RNTI) {
@ -168,7 +168,7 @@ void cc_worker::decode_pdcch_dl()
}
// Enqueue UL grants
phy->set_dl_pending_grant(dl_slot_cfg, dci_rx[i]);
phy.set_dl_pending_grant(dl_slot_cfg, dci_rx[i]);
}
if (logger.debug.enabled()) {
@ -194,7 +194,7 @@ void cc_worker::decode_pdcch_dl()
void cc_worker::decode_pdcch_ul()
{
std::array<srsran_dci_ul_nr_t, SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR> dci_rx = {};
srsue::mac_interface_phy_nr::sched_rnti_t rnti = phy->stack->get_ul_sched_rnti_nr(ul_slot_cfg.idx);
srsue::mac_interface_phy_nr::sched_rnti_t rnti = phy.stack->get_ul_sched_rnti_nr(ul_slot_cfg.idx);
// Skip search if no valid RNTI is given
if (rnti.id == SRSRAN_INVALID_RNTI) {
@ -219,7 +219,7 @@ void cc_worker::decode_pdcch_ul()
}
// Enqueue UL grants
phy->set_ul_pending_grant(dl_slot_cfg.idx, dci_rx[i]);
phy.set_ul_pending_grant(dl_slot_cfg.idx, dci_rx[i]);
}
}
@ -229,7 +229,7 @@ bool cc_worker::decode_pdsch_dl()
uint32_t pid = 0;
srsran_sch_cfg_nr_t pdsch_cfg = {};
srsran_pdsch_ack_resource_nr_t ack_resource = {};
if (not phy->get_dl_pending_grant(dl_slot_cfg.idx, pdsch_cfg, ack_resource, pid)) {
if (not phy.get_dl_pending_grant(dl_slot_cfg.idx, pdsch_cfg, ack_resource, pid)) {
// Early return if no grant was available
return true;
}
@ -242,13 +242,13 @@ bool cc_worker::decode_pdsch_dl()
mac_dl_grant.ndi = pdsch_cfg.grant.tb[0].ndi;
mac_dl_grant.tbs = pdsch_cfg.grant.tb[0].tbs / 8;
mac_dl_grant.tti = dl_slot_cfg.idx;
phy->stack->new_grant_dl(0, mac_dl_grant, &dl_action);
phy.stack->new_grant_dl(0, mac_dl_grant, &dl_action);
// Abort if MAC says it doesn't need the TB
if (not dl_action.tb.enabled) {
// Force positive ACK
if (pdsch_cfg.grant.rnti_type == srsran_rnti_type_c) {
phy->set_pending_ack(dl_slot_cfg.idx, ack_resource, true);
phy.set_pending_ack(dl_slot_cfg.idx, ack_resource, true);
}
logger.info("Decoding not required. Skipping PDSCH. ack_tti_tx=%d", TTI_ADD(dl_slot_cfg.idx, ack_resource.k1));
@ -302,17 +302,17 @@ bool cc_worker::decode_pdsch_dl()
// Enqueue PDSCH ACK information only if the RNTI is type C
if (pdsch_cfg.grant.rnti_type == srsran_rnti_type_c) {
phy->set_pending_ack(dl_slot_cfg.idx, ack_resource, pdsch_res.tb[0].crc);
phy.set_pending_ack(dl_slot_cfg.idx, ack_resource, pdsch_res.tb[0].crc);
}
// Notify MAC about PDSCH decoding result
mac_interface_phy_nr::tb_action_dl_result_t mac_dl_result = {};
mac_dl_result.ack = pdsch_res.tb[0].crc;
mac_dl_result.payload = mac_dl_result.ack ? std::move(data) : nullptr; // only pass data when successful
phy->stack->tb_decoded(cc_idx, mac_dl_grant, std::move(mac_dl_result));
phy.stack->tb_decoded(cc_idx, mac_dl_grant, std::move(mac_dl_result));
if (pdsch_cfg.grant.rnti_type == srsran_rnti_type_ra) {
phy->rar_grant_tti = dl_slot_cfg.idx;
phy.rar_grant_tti = dl_slot_cfg.idx;
}
if (pdsch_res.tb[0].crc) {
@ -321,7 +321,7 @@ bool cc_worker::decode_pdsch_dl()
dl_m.mcs = pdsch_cfg.grant.tb[0].mcs;
dl_m.fec_iters = pdsch_res.tb[0].avg_iter;
dl_m.evm = pdsch_res.evm[0];
phy->set_dl_metrics(dl_m);
phy.set_dl_metrics(dl_m);
}
return true;
@ -334,7 +334,7 @@ bool cc_worker::measure_csi()
srsran_csi_trs_measurements_t meas = {};
// Iterate all possible candidates
const std::array<bool, SRSRAN_SSB_NOF_CANDIDATES> position_in_burst = phy->cfg.ssb.position_in_burst;
const std::array<bool, SRSRAN_SSB_NOF_CANDIDATES> position_in_burst = phy.cfg.ssb.position_in_burst;
for (uint32_t ssb_idx = 0; ssb_idx < SRSRAN_SSB_NOF_CANDIDATES; ssb_idx++) {
// Skip SSB candidate if not enabled
if (not position_in_burst[ssb_idx]) {
@ -342,7 +342,7 @@ bool cc_worker::measure_csi()
}
// Measure SSB candidate
if (srsran_ssb_csi_measure(&ssb, phy->cfg.carrier.pci, ssb_idx, rx_buffer[0], &meas) < SRSRAN_SUCCESS) {
if (srsran_ssb_csi_measure(&ssb, phy.cfg.carrier.pci, ssb_idx, rx_buffer[0], &meas) < SRSRAN_SUCCESS) {
logger.error("Error measuring SSB");
return false;
}
@ -360,13 +360,13 @@ bool cc_worker::measure_csi()
ch_metrics.rsrq = 0.0f; // Not supported
ch_metrics.rssi = 0.0f; // Not supported
ch_metrics.sync_err =
meas.delay_us / (float)(ue_dl.fft->fft_plan.size * SRSRAN_SUBC_SPACING_NR(phy->cfg.carrier.scs));
phy->set_channel_metrics(ch_metrics);
meas.delay_us / (float)(ue_dl.fft->fft_plan.size * SRSRAN_SUBC_SPACING_NR(phy.cfg.carrier.scs));
phy.set_channel_metrics(ch_metrics);
// Compute synch metrics and report it to the PHY state
sync_metrics_t sync_metrics = {};
sync_metrics.cfo = meas.cfo_hz;
phy->set_sync_metrics(sync_metrics);
phy.set_sync_metrics(sync_metrics);
// Report SSB candidate channel measurement to the PHY state
// ...
@ -376,7 +376,7 @@ bool cc_worker::measure_csi()
// Iterate all NZP-CSI-RS marked as TRS and perform channel measurements
for (uint32_t resource_set_id = 0; resource_set_id < SRSRAN_PHCH_CFG_MAX_NOF_CSI_RS_SETS; resource_set_id++) {
// Select NZP-CSI-RS set
const srsran_csi_rs_nzp_set_t& nzp_set = phy->cfg.pdsch.nzp_csi_rs_sets[resource_set_id];
const srsran_csi_rs_nzp_set_t& nzp_set = phy.cfg.pdsch.nzp_csi_rs_sets[resource_set_id];
// Skip set if not set as TRS (it will be processed later)
if (not nzp_set.trs_info) {
@ -409,13 +409,13 @@ bool cc_worker::measure_csi()
ch_metrics.rsrq = 0.0f; // Not supported
ch_metrics.rssi = 0.0f; // Not supported
ch_metrics.sync_err =
trs_measurements.delay_us / (float)(ue_dl.fft->fft_plan.size * SRSRAN_SUBC_SPACING_NR(phy->cfg.carrier.scs));
phy->set_channel_metrics(ch_metrics);
trs_measurements.delay_us / (float)(ue_dl.fft->fft_plan.size * SRSRAN_SUBC_SPACING_NR(phy.cfg.carrier.scs));
phy.set_channel_metrics(ch_metrics);
// Compute synch metrics and report it to the PHY state
sync_metrics_t sync_metrics = {};
sync_metrics.cfo = trs_measurements.cfo_hz;
phy->set_sync_metrics(sync_metrics);
phy.set_sync_metrics(sync_metrics);
// Convert to CSI channel measurement and report new NZP-CSI-RS measurement to the PHY state
srsran_csi_channel_measurements_t measurements = {};
@ -425,13 +425,13 @@ bool cc_worker::measure_csi()
measurements.wideband_snr_db = trs_measurements.snr_dB;
measurements.nof_ports = 1; // Other values are not supported
measurements.K_csi_rs = (uint32_t)n;
phy->new_nzp_csi_rs_channel_measurement(measurements, resource_set_id);
phy.new_nzp_csi_rs_channel_measurement(measurements, resource_set_id);
}
// Iterate all NZP-CSI-RS not marked as TRS and perform channel measurements
for (uint32_t resource_set_id = 0; resource_set_id < SRSRAN_PHCH_CFG_MAX_NOF_CSI_RS_SETS; resource_set_id++) {
// Select NZP-CSI-RS set
const srsran_csi_rs_nzp_set_t& nzp_set = phy->cfg.pdsch.nzp_csi_rs_sets[resource_set_id];
const srsran_csi_rs_nzp_set_t& nzp_set = phy.cfg.pdsch.nzp_csi_rs_sets[resource_set_id];
// Skip set if set as TRS (it was processed previously)
if (nzp_set.trs_info) {
@ -458,7 +458,7 @@ bool cc_worker::measure_csi()
measurements.wideband_snr_db);
// Report new measurement to the PHY state
phy->new_nzp_csi_rs_channel_measurement(measurements, resource_set_id);
phy.new_nzp_csi_rs_channel_measurement(measurements, resource_set_id);
}
return true;
@ -472,7 +472,7 @@ bool cc_worker::work_dl()
}
// Check if it is a DL slot, if not skip
if (!srsran_tdd_nr_is_dl(&phy->cfg.tdd, 0, dl_slot_cfg.idx)) {
if (!srsran_tdd_nr_is_dl(&phy.cfg.tdd, 0, dl_slot_cfg.idx)) {
return true;
}
@ -503,7 +503,7 @@ bool cc_worker::work_dl()
bool cc_worker::work_ul()
{
// Check if it is a UL slot, if not skip
if (!srsran_tdd_nr_is_ul(&phy->cfg.tdd, 0, ul_slot_cfg.idx)) {
if (!srsran_tdd_nr_is_ul(&phy.cfg.tdd, 0, ul_slot_cfg.idx)) {
// No NR signal shall be transmitted
srsran_vec_cf_zero(tx_buffer[0], ue_ul.ifft.sf_sz);
return true;
@ -514,11 +514,11 @@ bool cc_worker::work_ul()
// Gather PDSCH ACK information
srsran_pdsch_ack_nr_t pdsch_ack = {};
bool has_ul_ack = phy->get_pending_ack(ul_slot_cfg.idx, pdsch_ack);
bool has_ul_ack = phy.get_pending_ack(ul_slot_cfg.idx, pdsch_ack);
// Request grant to PHY state for this transmit TTI
srsran_sch_cfg_nr_t pusch_cfg = {};
bool has_pusch_grant = phy->get_ul_pending_grant(ul_slot_cfg.idx, pusch_cfg, pid);
bool has_pusch_grant = phy.get_ul_pending_grant(ul_slot_cfg.idx, pusch_cfg, pid);
// If PDSCH UL ACK is available, load into UCI
if (has_ul_ack) {
@ -531,7 +531,7 @@ bool cc_worker::work_ul()
}
}
if (srsran_ue_dl_nr_gen_ack(&phy->cfg.harq_ack, &pdsch_ack, &uci_data) < SRSRAN_SUCCESS) {
if (srsran_ue_dl_nr_gen_ack(&phy.cfg.harq_ack, &pdsch_ack, &uci_data) < SRSRAN_SUCCESS) {
ERROR("Filling UCI ACK bits");
return false;
}
@ -539,11 +539,11 @@ bool cc_worker::work_ul()
// Add SR to UCI data only if there is no UL grant!
if (!has_ul_ack) {
phy->get_pending_sr(ul_slot_cfg.idx, uci_data);
phy.get_pending_sr(ul_slot_cfg.idx, uci_data);
}
// Add CSI reports to UCI data if available
phy->get_periodic_csi(ul_slot_cfg.idx, uci_data);
phy.get_periodic_csi(ul_slot_cfg.idx, uci_data);
if (has_pusch_grant) {
// Notify MAC about PUSCH found grant
@ -556,7 +556,7 @@ bool cc_worker::work_ul()
mac_ul_grant.ndi = pusch_cfg.grant.tb[0].ndi;
mac_ul_grant.rv = pusch_cfg.grant.tb[0].rv;
mac_ul_grant.is_rar_grant = (pusch_cfg.grant.rnti_type == srsran_rnti_type_ra);
phy->stack->new_grant_ul(0, mac_ul_grant, &ul_action);
phy.stack->new_grant_ul(0, mac_ul_grant, &ul_action);
// Don't process further if MAC can't provide PDU
if (not ul_action.tb.enabled) {
@ -565,7 +565,7 @@ bool cc_worker::work_ul()
}
// Set UCI configuration following procedures
srsran_ra_ul_set_grant_uci_nr(&phy->cfg.carrier, &phy->cfg.pusch, &uci_data.cfg, &pusch_cfg);
srsran_ra_ul_set_grant_uci_nr(&phy.cfg.carrier, &phy.cfg.pusch, &uci_data.cfg, &pusch_cfg);
// Assigning MAC provided values to PUSCH config structs
pusch_cfg.grant.tb[0].softbuffer.tx = ul_action.tb.softbuffer;
@ -612,18 +612,18 @@ bool cc_worker::work_ul()
ul_metrics_t ul_m = {};
ul_m.mcs = pusch_cfg.grant.tb[0].mcs;
ul_m.power = srsran_convert_power_to_dB(srsran_vec_avg_power_cf(tx_buffer[0], ue_ul.ifft.sf_sz));
phy->set_ul_metrics(ul_m);
phy.set_ul_metrics(ul_m);
} else if (srsran_uci_nr_total_bits(&uci_data.cfg) > 0) {
// Get PUCCH resource
srsran_pucch_nr_resource_t resource = {};
if (srsran_ra_ul_nr_pucch_resource(&phy->cfg.pucch, &uci_data.cfg, &resource) < SRSRAN_SUCCESS) {
if (srsran_ra_ul_nr_pucch_resource(&phy.cfg.pucch, &uci_data.cfg, &resource) < SRSRAN_SUCCESS) {
ERROR("Selecting PUCCH resource");
return false;
}
// Encode PUCCH message
if (srsran_ue_ul_nr_encode_pucch(&ue_ul, &ul_slot_cfg, &phy->cfg.pucch.common, &resource, &uci_data) <
if (srsran_ue_ul_nr_encode_pucch(&ue_ul, &ul_slot_cfg, &phy.cfg.pucch.common, &resource, &uci_data) <
SRSRAN_SUCCESS) {
ERROR("Encoding PUCCH");
return false;

@ -27,10 +27,10 @@ static int plot_worker_id = -1;
namespace srsue {
namespace nr {
sf_worker::sf_worker(phy_common* phy_, state* phy_state_, srslog::basic_logger& log) :
phy_state(phy_state_), phy(phy_), logger(log)
sf_worker::sf_worker(srsran::phy_common_interface& common_, state& phy_state_, srslog::basic_logger& log) :
phy_state(phy_state_), common(common_), logger(log)
{
for (uint32_t i = 0; i < phy_state->args.nof_carriers; i++) {
for (uint32_t i = 0; i < phy_state.args.nof_carriers; i++) {
cc_worker* w = new cc_worker(i, log, phy_state);
cc_workers.push_back(std::unique_ptr<cc_worker>(w));
}
@ -79,8 +79,8 @@ void sf_worker::work_imp()
}
// Align workers, wait for previous workers to finish DL processing before starting UL processing
phy_state->dl_ul_semaphore.wait(this);
phy_state->dl_ul_semaphore.release();
phy_state.dl_ul_semaphore.wait(this);
phy_state.dl_ul_semaphore.release();
// Check if PRACH is available
if (prach_ptr != nullptr) {
@ -88,14 +88,14 @@ void sf_worker::work_imp()
tx_buffer.set(0, prach_ptr);
// Notify MAC about PRACH transmission
phy_state->stack->prach_sent(TTI_TX(tti_rx),
srsran_prach_nr_start_symbol_fr1_unpaired(phy_state->cfg.prach.config_idx),
SRSRAN_SLOT_NR_MOD(phy_state->cfg.carrier.scs, TTI_TX(tti_rx)),
0,
0);
phy_state.stack->prach_sent(TTI_TX(tti_rx),
srsran_prach_nr_start_symbol_fr1_unpaired(phy_state.cfg.prach.config_idx),
SRSRAN_SLOT_NR_MOD(phy_state.cfg.carrier.scs, TTI_TX(tti_rx)),
0,
0);
// Transmit NR PRACH
phy->worker_end(this, false, tx_buffer, dummy_ts, true);
common.worker_end(this, tx_buffer, dummy_ts, true);
// Reset PRACH pointer
prach_ptr = nullptr;
@ -114,7 +114,7 @@ void sf_worker::work_imp()
}
// Always call worker_end before returning
phy->worker_end(this, false, tx_buffer, dummy_ts, true);
common.worker_end(this, tx_buffer, dummy_ts, true);
// Tell the plotting thread to draw the plots
#ifdef ENABLE_GUI

@ -16,7 +16,10 @@ namespace nr {
worker_pool::worker_pool(uint32_t max_workers) : pool(max_workers), logger(srslog::fetch_basic_logger("PHY-NR")) {}
bool worker_pool::init(const phy_args_nr_t& args, phy_common* common, stack_interface_phy_nr* stack_, int prio)
bool worker_pool::init(const phy_args_nr_t& args,
srsran::phy_common_interface& common,
stack_interface_phy_nr* stack_,
int prio)
{
phy_state.stack = stack_;
phy_state.args = args;
@ -43,7 +46,7 @@ bool worker_pool::init(const phy_args_nr_t& args, phy_common* common, stack_inte
log.set_level(srslog::str_to_basic_level(args.log.phy_level));
log.set_hex_dump_max_size(args.log.phy_hex_limit);
auto w = new sf_worker(common, &phy_state, log);
auto w = new sf_worker(common, phy_state, log);
pool.init_worker(i, w, prio, args.worker_cpu_mask);
workers.push_back(std::unique_ptr<sf_worker>(w));
}

@ -615,7 +615,7 @@ void phy::set_mch_period_stop(uint32_t stop)
int phy::init(const phy_args_nr_t& args_, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_)
{
if (!nr_workers.init(args_, &common, stack_, WORKERS_THREAD_PRIO)) {
if (!nr_workers.init(args_, common, stack_, WORKERS_THREAD_PRIO)) {
return SRSRAN_ERROR;
}

@ -531,12 +531,10 @@ bool phy_common::get_dl_pending_ack(srsran_ul_sf_cfg_t* sf, uint32_t cc_idx, srs
* Each worker uses this function to indicate that all processing is done and data is ready for transmission or
* there is no transmission at all (tx_enable). In that case, the end of burst message will be sent to the radio
*/
void phy_common::worker_end(void* tx_sem_id,
bool tx_enable,
srsran::rf_buffer_t& buffer,
srsran::rf_timestamp_t& tx_time,
bool is_nr)
void phy_common::worker_end(void* tx_sem_id, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr)
{
bool tx_enable = buffer.get_nof_samples() > 0;
// Wait for the green light to transmit in the current TTI
semaphore.wait(tx_sem_id);

@ -19,3 +19,5 @@ if (ZEROMQ_FOUND AND ENABLE_ZMQ_TEST)
endforeach (cell_n_prb)
endforeach (num_cc)
endif (ZEROMQ_FOUND AND ENABLE_ZMQ_TEST)
add_subdirectory(phy)

@ -0,0 +1,23 @@
#
# 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.
#
add_executable(nr_phy_test nr_phy_test.cc)
target_link_libraries(nr_phy_test
srsue_phy_nr
srsue_phy
srsran_common
srsran_phy
srsran_radio
srsenb_phy
${CMAKE_THREAD_LIBS_INIT}
${Boost_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${Boost_LIBRARIES}
${ATOMIC_LIBS})
add_nr_test(nr_phy_test nr_phy_test)

@ -0,0 +1,111 @@
/**
*
* \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 "srsenb/hdr/phy/nr/worker_pool.h"
#include "srsran/common/test_common.h"
#include "srsue/hdr/phy/nr/worker_pool.h"
class phy_common : public srsran::phy_common_interface
{
public:
void worker_end(void* h, srsran::rf_buffer_t& buffer, srsran::rf_timestamp_t& tx_time, bool is_nr) override {}
};
class ue_dummy_stack : public srsue::stack_interface_phy_nr
{
public:
void in_sync() override {}
void out_of_sync() override {}
void run_tti(const uint32_t tti) override {}
int sf_indication(const uint32_t tti) override { return 0; }
sched_rnti_t get_dl_sched_rnti_nr(const uint32_t tti) override { return sched_rnti_t(); }
sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti) override { return sched_rnti_t(); }
void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) override {}
void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result) override {}
void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action) override {}
void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id) override {}
bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) override { return false; }
};
class test_bench
{
private:
srsenb::nr::worker_pool gnb_phy;
phy_common gnb_phy_com;
srsue::nr::worker_pool ue_phy;
phy_common ue_phy_com;
ue_dummy_stack ue_stack;
bool initialised = false;
public:
struct args_t {
uint32_t nof_threads = 6;
uint32_t nof_prb = 52;
bool parse(int argc, char** argv);
};
test_bench(const args_t& args) : ue_phy(args.nof_threads), gnb_phy(args.nof_threads)
{
// Prepare cell list
srsenb::phy_cell_cfg_list_nr_t cell_list(1);
cell_list[0].carrier.nof_prb = args.nof_prb;
// Prepare gNb PHY arguments
srsenb::phy_args_t gnb_phy_args = {};
// Initialise gnb
if (not gnb_phy.init(cell_list, gnb_phy_args, gnb_phy_com, srslog::get_default_sink(), 31)) {
return;
}
// Prepare PHY
srsue::phy_args_nr_t ue_phy_args = {};
// Initialise UE PHY
if (not ue_phy.init(ue_phy_args, ue_phy_com, &ue_stack, 31)) {
return;
}
initialised = true;
}
~test_bench()
{
gnb_phy.stop();
ue_phy.stop();
}
bool is_initialised() const { return initialised; }
};
bool test_bench::args_t::parse(int argc, char** argv)
{
return true;
}
int main(int argc, char** argv)
{
test_bench::args_t args = {};
// Parse arguments
TESTASSERT(args.parse(argc, argv));
// Create test bench
test_bench tb(args);
// Assert bench is initialised correctly
TESTASSERT(tb.is_initialised());
// If reached here, the test is successful
return SRSRAN_SUCCESS;
}
Loading…
Cancel
Save