nr,gnb,mac: implement zero-copy get_dl_sched/get_ul_sched NR scheduler interface

master
Francisco 3 years ago committed by Andre Puschmann
parent 2eaf9add48
commit 8d719db43d

@ -280,8 +280,8 @@ public:
}; };
virtual int slot_indication(const srsran_slot_cfg_t& slot_cfg) = 0; virtual int slot_indication(const srsran_slot_cfg_t& slot_cfg) = 0;
virtual int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) = 0; virtual dl_sched_t* get_dl_sched(const srsran_slot_cfg_t& slot_cfg) = 0;
virtual int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) = 0; virtual ul_sched_t* get_ul_sched(const srsran_slot_cfg_t& slot_cfg) = 0;
virtual int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) = 0; virtual int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) = 0;
virtual int pusch_info(const srsran_slot_cfg_t& slot_cfg, pusch_info_t& pusch_info) = 0; virtual int pusch_info(const srsran_slot_cfg_t& slot_cfg, pusch_info_t& pusch_info) = 0;
virtual void rach_detected(const rach_info_t& rach_info) = 0; virtual void rach_detected(const rach_info_t& rach_info) = 0;

@ -72,8 +72,8 @@ public:
void toggle_padding() override {} void toggle_padding() override {}
int slot_indication(const srsran_slot_cfg_t& slot_cfg) override; int slot_indication(const srsran_slot_cfg_t& slot_cfg) override;
int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override; dl_sched_t* get_dl_sched(const srsran_slot_cfg_t& slot_cfg) override;
int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override; ul_sched_t* get_ul_sched(const srsran_slot_cfg_t& slot_cfg) override;
int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override; int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override;
int pusch_info(const srsran_slot_cfg_t& slot_cfg, pusch_info_t& pusch_info) override; int pusch_info(const srsran_slot_cfg_t& slot_cfg, pusch_info_t& pusch_info) override;
void rach_detected(const rach_info_t& rach_info) override; void rach_detected(const rach_info_t& rach_info) override;

@ -64,8 +64,8 @@ public:
// Interface for PHY // Interface for PHY
int slot_indication(const srsran_slot_cfg_t& slot_cfg) override; int slot_indication(const srsran_slot_cfg_t& slot_cfg) override;
int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override; dl_sched_t* get_dl_sched(const srsran_slot_cfg_t& slot_cfg) override;
int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override; ul_sched_t* get_ul_sched(const srsran_slot_cfg_t& slot_cfg) override;
int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override; int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override;
int pusch_info(const srsran_slot_cfg_t& slot_cfg, pusch_info_t& pusch_info) override; int pusch_info(const srsran_slot_cfg_t& slot_cfg, pusch_info_t& pusch_info) override;
void rach_detected(const rach_info_t& rach_info) override; void rach_detected(const rach_info_t& rach_info) override;

@ -31,8 +31,6 @@ class cc_worker;
} // namespace sched_nr_impl } // namespace sched_nr_impl
class ul_sched_result_buffer;
class sched_nr final : public sched_nr_interface class sched_nr final : public sched_nr_interface
{ {
public: public:
@ -54,8 +52,8 @@ public:
/// Called once per slot in a non-concurrent fashion /// Called once per slot in a non-concurrent fashion
void slot_indication(slot_point slot_tx) override; void slot_indication(slot_point slot_tx) override;
int get_dl_sched(slot_point pdsch_tti, uint32_t cc, dl_res_t& result) override; dl_res_t* get_dl_sched(slot_point pdsch_tti, uint32_t cc) override;
int get_ul_sched(slot_point pusch_tti, uint32_t cc, ul_res_t& result) override; ul_res_t* get_ul_sched(slot_point pusch_tti, uint32_t cc) override;
void get_metrics(mac_metrics_t& metrics); void get_metrics(mac_metrics_t& metrics);
@ -77,9 +75,6 @@ private:
using ue_map_t = sched_nr_impl::ue_map_t; using ue_map_t = sched_nr_impl::ue_map_t;
ue_map_t ue_db; ue_map_t ue_db;
// management of Sched Result buffering
std::unique_ptr<ul_sched_result_buffer> pending_results;
// Feedback management // Feedback management
class event_manager; class event_manager;
std::unique_ptr<event_manager> pending_events; std::unique_ptr<event_manager> pending_events;

@ -49,15 +49,9 @@ struct bwp_slot_grid {
bwp_rb_bitmap dl_prbs; bwp_rb_bitmap dl_prbs;
bwp_rb_bitmap ul_prbs; bwp_rb_bitmap ul_prbs;
ssb_list ssb; dl_sched_res_t dl;
nzp_csi_rs_list nzp_csi_rs; ul_sched_t ul;
pdcch_dl_list_t dl_pdcchs;
pdcch_ul_list_t ul_pdcchs;
pdsch_list_t pdschs;
pucch_list_t pucch;
sched_rar_list_t rar;
slot_coreset_list coresets; slot_coreset_list coresets;
pusch_list_t puschs;
harq_ack_list_t pending_acks; harq_ack_list_t pending_acks;
srsran::unique_pool_ptr<tx_harq_softbuffer> rar_softbuffer; srsran::unique_pool_ptr<tx_harq_softbuffer> rar_softbuffer;

@ -108,9 +108,8 @@ public:
using sched_rar_list_t = srsran::bounded_vector<rar_t, MAX_GRANTS>; using sched_rar_list_t = srsran::bounded_vector<rar_t, MAX_GRANTS>;
struct dl_res_t { struct dl_res_t {
sched_rar_list_t& rar; dl_sched_t phy;
dl_sched_t& dl_sched; sched_rar_list_t rar;
dl_res_t(sched_rar_list_t& rar_, dl_sched_t& dl_sched_) : rar(rar_), dl_sched(dl_sched_) {}
}; };
virtual ~sched_nr_interface() = default; virtual ~sched_nr_interface() = default;
@ -119,8 +118,8 @@ public:
virtual void ue_rem(uint16_t rnti) = 0; virtual void ue_rem(uint16_t rnti) = 0;
virtual void slot_indication(slot_point slot_tx) = 0; virtual void slot_indication(slot_point slot_tx) = 0;
virtual int get_dl_sched(slot_point slot_rx, uint32_t cc, dl_res_t& result) = 0; virtual dl_res_t* get_dl_sched(slot_point slot_rx, uint32_t cc) = 0;
virtual int get_ul_sched(slot_point slot_rx, uint32_t cc, ul_res_t& result) = 0; virtual ul_res_t* get_ul_sched(slot_point slot_rx, uint32_t cc) = 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;
virtual void ul_crc_info(uint16_t rnti, uint32_t cc, uint32_t pid, bool crc) = 0; virtual void ul_crc_info(uint16_t rnti, uint32_t cc, uint32_t pid, bool crc) = 0;

@ -37,7 +37,8 @@ public:
void dl_rach_info(const sched_nr_interface::rar_info_t& rar_info); void dl_rach_info(const sched_nr_interface::rar_info_t& rar_info);
void run_slot(slot_point pdcch_slot, ue_map_t& ue_db_, dl_sched_res_t& dl_res, ul_sched_t& ul_res); dl_sched_res_t* run_slot(slot_point pdcch_slot, ue_map_t& ue_db_);
ul_sched_t* get_ul_sched(slot_point sl);
// const params // const params
const cell_params_t& cfg; const cell_params_t& cfg;
@ -47,9 +48,6 @@ public:
srsran::bounded_vector<bwp_manager, SCHED_NR_MAX_BWP_PER_CELL> bwps; srsran::bounded_vector<bwp_manager, SCHED_NR_MAX_BWP_PER_CELL> bwps;
private: private:
/// Derive the remaining scheduling parameters and save result
bool save_sched_result(dl_sched_res_t& dl_res, ul_sched_t& ul_res, slot_point slot_tx);
void alloc_dl_ues(bwp_slot_allocator& bwp_alloc); void alloc_dl_ues(bwp_slot_allocator& bwp_alloc);
void alloc_ul_ues(bwp_slot_allocator& bwp_alloc); void alloc_ul_ues(bwp_slot_allocator& bwp_alloc);
void postprocess_decisions(bwp_slot_allocator& bwp_alloc); void postprocess_decisions(bwp_slot_allocator& bwp_alloc);

@ -142,13 +142,13 @@ void slot_worker::set_context(const srsran::phy_common_interface::worker_context
bool slot_worker::work_ul() bool slot_worker::work_ul()
{ {
stack_interface_phy_nr::ul_sched_t ul_sched = {}; stack_interface_phy_nr::ul_sched_t* ul_sched = stack.get_ul_sched(ul_slot_cfg);
if (stack.get_ul_sched(ul_slot_cfg, ul_sched) < SRSRAN_SUCCESS) { if (ul_sched == nullptr) {
logger.error("Error retrieving UL scheduling"); logger.error("Error retrieving UL scheduling");
return false; return false;
} }
if (ul_sched.pucch.empty() && ul_sched.pusch.empty()) { if (ul_sched->pucch.empty() && ul_sched->pusch.empty()) {
// early exit if nothing has been scheduled // early exit if nothing has been scheduled
return true; return true;
} }
@ -160,7 +160,7 @@ bool slot_worker::work_ul()
} }
// For each PUCCH... // For each PUCCH...
for (stack_interface_phy_nr::pucch_t& pucch : ul_sched.pucch) { for (stack_interface_phy_nr::pucch_t& pucch : ul_sched->pucch) {
srsran::bounded_vector<stack_interface_phy_nr::pucch_info_t, stack_interface_phy_nr::MAX_PUCCH_CANDIDATES> srsran::bounded_vector<stack_interface_phy_nr::pucch_info_t, stack_interface_phy_nr::MAX_PUCCH_CANDIDATES>
pucch_info(pucch.candidates.size()); pucch_info(pucch.candidates.size());
@ -211,7 +211,7 @@ bool slot_worker::work_ul()
} }
// For each PUSCH... // For each PUSCH...
for (stack_interface_phy_nr::pusch_t& pusch : ul_sched.pusch) { for (stack_interface_phy_nr::pusch_t& pusch : ul_sched->pusch) {
// Prepare PUSCH // Prepare PUSCH
stack_interface_phy_nr::pusch_info_t pusch_info = {}; stack_interface_phy_nr::pusch_info_t pusch_info = {};
pusch_info.uci_cfg = pusch.sch.uci; pusch_info.uci_cfg = pusch.sch.uci;
@ -265,14 +265,13 @@ bool slot_worker::work_dl()
sync.wait(this); sync.wait(this);
// Retrieve Scheduling for the current processing DL slot // Retrieve Scheduling for the current processing DL slot
stack_interface_phy_nr::dl_sched_t dl_sched = {}; const stack_interface_phy_nr::dl_sched_t* dl_sched_ptr = stack.get_dl_sched(dl_slot_cfg);
bool dl_sched_fail = stack.get_dl_sched(dl_slot_cfg, dl_sched) < SRSRAN_SUCCESS;
// Releases synchronization lock and allow next worker to retrieve scheduling results // Releases synchronization lock and allow next worker to retrieve scheduling results
sync.release(); sync.release();
// Abort if the scheduling failed // Abort if the scheduling failed
if (dl_sched_fail) { if (dl_sched_ptr == nullptr) {
logger.error("Error retrieving DL scheduling"); logger.error("Error retrieving DL scheduling");
return false; return false;
} }
@ -283,7 +282,7 @@ bool slot_worker::work_dl()
} }
// Encode PDCCH for DL transmissions // Encode PDCCH for DL transmissions
for (const stack_interface_phy_nr::pdcch_dl_t& pdcch : dl_sched.pdcch_dl) { for (const stack_interface_phy_nr::pdcch_dl_t& pdcch : dl_sched_ptr->pdcch_dl) {
// Set PDCCH configuration, including DCI dedicated // Set PDCCH configuration, including DCI dedicated
if (srsran_gnb_dl_set_pdcch_config(&gnb_dl, &pdcch_cfg, &pdcch.dci_cfg) < SRSRAN_SUCCESS) { if (srsran_gnb_dl_set_pdcch_config(&gnb_dl, &pdcch_cfg, &pdcch.dci_cfg) < SRSRAN_SUCCESS) {
logger.error("PDCCH: Error setting DL configuration"); logger.error("PDCCH: Error setting DL configuration");
@ -305,7 +304,7 @@ bool slot_worker::work_dl()
} }
// Encode PDCCH for UL transmissions // Encode PDCCH for UL transmissions
for (const stack_interface_phy_nr::pdcch_ul_t& pdcch : dl_sched.pdcch_ul) { for (const stack_interface_phy_nr::pdcch_ul_t& pdcch : dl_sched_ptr->pdcch_ul) {
// Set PDCCH configuration, including DCI dedicated // Set PDCCH configuration, including DCI dedicated
if (srsran_gnb_dl_set_pdcch_config(&gnb_dl, &pdcch_cfg, &pdcch.dci_cfg) < SRSRAN_SUCCESS) { if (srsran_gnb_dl_set_pdcch_config(&gnb_dl, &pdcch_cfg, &pdcch.dci_cfg) < SRSRAN_SUCCESS) {
logger.error("PDCCH: Error setting DL configuration"); logger.error("PDCCH: Error setting DL configuration");
@ -327,7 +326,7 @@ bool slot_worker::work_dl()
} }
// Encode PDSCH // Encode PDSCH
for (stack_interface_phy_nr::pdsch_t& pdsch : dl_sched.pdsch) { for (const stack_interface_phy_nr::pdsch_t& pdsch : dl_sched_ptr->pdsch) {
// convert MAC to PHY buffer data structures // convert MAC to PHY buffer data structures
uint8_t* data[SRSRAN_MAX_TB] = {}; uint8_t* data[SRSRAN_MAX_TB] = {};
for (uint32_t i = 0; i < SRSRAN_MAX_TB; ++i) { for (uint32_t i = 0; i < SRSRAN_MAX_TB; ++i) {
@ -358,7 +357,7 @@ bool slot_worker::work_dl()
} }
// Put NZP-CSI-RS // Put NZP-CSI-RS
for (srsran_csi_rs_nzp_resource_t& nzp_csi_rs : dl_sched.nzp_csi_rs) { for (const srsran_csi_rs_nzp_resource_t& nzp_csi_rs : dl_sched_ptr->nzp_csi_rs) {
if (srsran_gnb_dl_nzp_csi_rs_put(&gnb_dl, &dl_slot_cfg, &nzp_csi_rs) < SRSRAN_SUCCESS) { if (srsran_gnb_dl_nzp_csi_rs_put(&gnb_dl, &dl_slot_cfg, &nzp_csi_rs) < SRSRAN_SUCCESS) {
logger.error("NZP-CSI-RS: Error putting signal"); logger.error("NZP-CSI-RS: Error putting signal");
return false; return false;
@ -369,7 +368,7 @@ bool slot_worker::work_dl()
srsran_gnb_dl_gen_signal(&gnb_dl); srsran_gnb_dl_gen_signal(&gnb_dl);
// Add SSB to the baseband signal // Add SSB to the baseband signal
for (const stack_interface_phy_nr::ssb_t& ssb : dl_sched.ssb) { for (const stack_interface_phy_nr::ssb_t& ssb : dl_sched_ptr->ssb) {
if (srsran_gnb_dl_add_ssb(&gnb_dl, &ssb.pbch_msg, dl_slot_cfg.idx) < SRSRAN_SUCCESS) { if (srsran_gnb_dl_add_ssb(&gnb_dl, &ssb.pbch_msg, dl_slot_cfg.idx) < SRSRAN_SUCCESS) {
logger.error("SSB: Error putting signal"); logger.error("SSB: Error putting signal");
return false; return false;

@ -186,13 +186,13 @@ int gnb_stack_nr::slot_indication(const srsran_slot_cfg_t& slot_cfg)
{ {
return mac.slot_indication(slot_cfg); return mac.slot_indication(slot_cfg);
} }
int gnb_stack_nr::get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) gnb_stack_nr::dl_sched_t* gnb_stack_nr::get_dl_sched(const srsran_slot_cfg_t& slot_cfg)
{ {
return mac.get_dl_sched(slot_cfg, dl_sched); return mac.get_dl_sched(slot_cfg);
} }
int gnb_stack_nr::get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) gnb_stack_nr::ul_sched_t* gnb_stack_nr::get_ul_sched(const srsran_slot_cfg_t& slot_cfg)
{ {
return mac.get_ul_sched(slot_cfg, ul_sched); return mac.get_ul_sched(slot_cfg);
} }
int gnb_stack_nr::pucch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_phy_nr::pucch_info_t& pucch_info) int gnb_stack_nr::pucch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_phy_nr::pucch_info_t& pucch_info)
{ {

@ -293,7 +293,7 @@ int mac_nr::slot_indication(const srsran_slot_cfg_t& slot_cfg)
return 0; return 0;
} }
int mac_nr::get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) mac_nr::dl_sched_t* mac_nr::get_dl_sched(const srsran_slot_cfg_t& slot_cfg)
{ {
slot_point pdsch_slot = srsran::slot_point{NUMEROLOGY_IDX, slot_cfg.idx}; slot_point pdsch_slot = srsran::slot_point{NUMEROLOGY_IDX, slot_cfg.idx};
@ -303,17 +303,15 @@ int mac_nr::get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched
sched->slot_indication(pdsch_slot); sched->slot_indication(pdsch_slot);
// Run DL Scheduler for CC // Run DL Scheduler for CC
sched_nr_interface::sched_rar_list_t rar_list; sched_nr::dl_res_t* dl_res = sched->get_dl_sched(pdsch_slot, 0);
sched_nr_interface::dl_res_t dl_res(rar_list, dl_sched); if (dl_res == nullptr) {
int ret = sched->get_dl_sched(pdsch_slot, 0, dl_res); return nullptr;
if (ret != SRSRAN_SUCCESS) {
return ret;
} }
// Generate MAC DL PDUs // Generate MAC DL PDUs
uint32_t rar_count = 0; uint32_t rar_count = 0;
srsran::rwlock_read_guard rw_lock(rwmutex); srsran::rwlock_read_guard rw_lock(rwmutex);
for (pdsch_t& pdsch : dl_sched.pdsch) { for (pdsch_t& pdsch : dl_res->phy.pdsch) {
if (pdsch.sch.grant.rnti_type == srsran_rnti_type_c) { if (pdsch.sch.grant.rnti_type == srsran_rnti_type_c) {
uint16_t rnti = pdsch.sch.grant.rnti; uint16_t rnti = pdsch.sch.grant.rnti;
if (not is_rnti_active_nolock(rnti)) { if (not is_rnti_active_nolock(rnti)) {
@ -332,7 +330,7 @@ int mac_nr::get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched
} }
} }
} else if (pdsch.sch.grant.rnti_type == srsran_rnti_type_ra) { } else if (pdsch.sch.grant.rnti_type == srsran_rnti_type_ra) {
sched_nr_interface::rar_t& rar = dl_res.rar[rar_count++]; sched_nr_interface::rar_t& rar = dl_res->rar[rar_count++];
// for RARs we could actually move the byte_buffer to the PHY, as there are no retx // for RARs we could actually move the byte_buffer to the PHY, as there are no retx
pdsch.data[0] = assemble_rar(rar.grants); pdsch.data[0] = assemble_rar(rar.grants);
} }
@ -340,23 +338,22 @@ int mac_nr::get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched
for (auto& u : ue_db) { for (auto& u : ue_db) {
u.second->metrics_cnt(); u.second->metrics_cnt();
} }
return SRSRAN_SUCCESS;
return &dl_res->phy;
} }
int mac_nr::get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) mac_nr::ul_sched_t* mac_nr::get_ul_sched(const srsran_slot_cfg_t& slot_cfg)
{ {
int ret = 0;
slot_point pusch_slot = srsran::slot_point{NUMEROLOGY_IDX, slot_cfg.idx}; slot_point pusch_slot = srsran::slot_point{NUMEROLOGY_IDX, slot_cfg.idx};
ret = sched->get_ul_sched(pusch_slot, 0, ul_sched); ul_sched_t* ul_sched = sched->get_ul_sched(pusch_slot, 0);
srsran::rwlock_read_guard rw_lock(rwmutex); srsran::rwlock_read_guard rw_lock(rwmutex);
for (auto& pusch : ul_sched.pusch) { for (auto& pusch : ul_sched->pusch) {
if (ue_db.contains(pusch.sch.grant.rnti)) { if (ue_db.contains(pusch.sch.grant.rnti)) {
ue_db[pusch.sch.grant.rnti]->metrics_ul_mcs(pusch.sch.grant.tb->mcs); ue_db[pusch.sch.grant.rnti]->metrics_ul_mcs(pusch.sch.grant.tb->mcs);
} }
} }
return ret; return ul_sched;
} }
int mac_nr::pucch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_phy_nr::pucch_info_t& pucch_info) int mac_nr::pucch_info(const srsran_slot_cfg_t& slot_cfg, const mac_interface_phy_nr::pucch_info_t& pucch_info)

@ -27,47 +27,6 @@ static int assert_ue_cfg_valid(uint16_t rnti, const sched_nr_interface::ue_cfg_t
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ul_sched_result_buffer
{
public:
explicit ul_sched_result_buffer(uint32_t nof_cc_)
{
for (auto& v : results) {
v.resize(nof_cc_);
}
}
ul_sched_t& add_ul_result(slot_point tti, uint32_t cc)
{
if (not has_ul_result(tti, cc)) {
results[tti.to_uint()][cc].slot_ul = tti;
results[tti.to_uint()][cc].ul_res = {};
}
return results[tti.to_uint()][cc].ul_res;
}
bool has_ul_result(slot_point tti, uint32_t cc) const { return results[tti.to_uint()][cc].slot_ul == tti; }
ul_sched_t pop_ul_result(slot_point tti, uint32_t cc)
{
if (has_ul_result(tti, cc)) {
results[tti.to_uint()][cc].slot_ul.clear();
return results[tti.to_uint()][cc].ul_res;
}
return {};
}
private:
struct slot_result_t {
slot_point slot_ul;
ul_sched_t ul_res;
};
srsran::circular_array<std::vector<slot_result_t>, TTIMOD_SZ> results;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Class that stores events that are not specific to a CC (e.g. SRs, removal of UEs, buffer state updates) /// Class that stores events that are not specific to a CC (e.g. SRs, removal of UEs, buffer state updates)
class sched_nr::event_manager class sched_nr::event_manager
{ {
@ -342,7 +301,6 @@ int sched_nr::config(const sched_args_t& sched_cfg, srsran::const_span<cell_cfg_
cfg.cells.emplace_back(cc, cell_list[cc], cfg.sched_cfg); cfg.cells.emplace_back(cc, cell_list[cc], cfg.sched_cfg);
} }
pending_results.reset(new ul_sched_result_buffer(cell_list.size()));
pending_events.reset(new event_manager{cfg}); pending_events.reset(new event_manager{cfg});
// Initiate cell-specific schedulers // Initiate cell-specific schedulers
@ -416,13 +374,10 @@ void sched_nr::slot_indication(slot_point slot_tx)
} }
/// Generate {pdcch_slot,cc} scheduling decision /// Generate {pdcch_slot,cc} scheduling decision
int sched_nr::get_dl_sched(slot_point pdsch_tti, uint32_t cc, dl_res_t& result) sched_nr::dl_res_t* sched_nr::get_dl_sched(slot_point pdsch_tti, uint32_t cc)
{ {
srsran_assert(pdsch_tti == current_slot_tx, "Unexpected pdsch_tti slot received"); srsran_assert(pdsch_tti == current_slot_tx, "Unexpected pdsch_tti slot received");
// Copy UL results to intermediate buffer
ul_res_t& ul_res = pending_results->add_ul_result(pdsch_tti, cc);
// process non-cc specific feedback if pending (e.g. SRs, buffer state updates, UE config) for non-CA UEs // process non-cc specific feedback if pending (e.g. SRs, buffer state updates, UE config) for non-CA UEs
pending_events->process_cc_events(ue_db, cc); pending_events->process_cc_events(ue_db, cc);
@ -434,7 +389,7 @@ int sched_nr::get_dl_sched(slot_point pdsch_tti, uint32_t cc, dl_res_t& result)
} }
// Process pending CC-specific feedback, generate {slot_idx,cc} scheduling decision // Process pending CC-specific feedback, generate {slot_idx,cc} scheduling decision
cc_workers[cc]->run_slot(pdsch_tti, ue_db, result, ul_res); sched_nr::dl_res_t* ret = cc_workers[cc]->run_slot(pdsch_tti, ue_db);
// decrement the number of active workers // decrement the number of active workers
int rem_workers = worker_count.fetch_sub(1, std::memory_order_release) - 1; int rem_workers = worker_count.fetch_sub(1, std::memory_order_release) - 1;
@ -444,21 +399,13 @@ int sched_nr::get_dl_sched(slot_point pdsch_tti, uint32_t cc, dl_res_t& result)
// TODO: Sync sched results with ue_db state // TODO: Sync sched results with ue_db state
} }
return SRSRAN_SUCCESS; return ret;
} }
/// Fetch {ul_slot,cc} UL scheduling decision /// Fetch {ul_slot,cc} UL scheduling decision
int sched_nr::get_ul_sched(slot_point slot_ul, uint32_t cc, ul_res_t& result) sched_nr::ul_res_t* sched_nr::get_ul_sched(slot_point slot_ul, uint32_t cc)
{ {
if (not pending_results->has_ul_result(slot_ul, cc)) { return cc_workers[cc]->get_ul_sched(slot_ul);
// sched result hasn't been generated
result.pucch.clear();
result.pusch.clear();
return SRSRAN_SUCCESS;
}
result = pending_results->pop_ul_result(slot_ul, cc);
return SRSRAN_SUCCESS;
} }
void sched_nr::get_metrics(mac_metrics_t& metrics) void sched_nr::get_metrics(mac_metrics_t& metrics)

@ -27,7 +27,7 @@ bwp_slot_grid::bwp_slot_grid(const bwp_params_t& bwp_cfg_, uint32_t slot_idx_) :
for (uint32_t cs_idx = 0; cs_idx < SRSRAN_UE_DL_NR_MAX_NOF_CORESET; ++cs_idx) { for (uint32_t cs_idx = 0; cs_idx < SRSRAN_UE_DL_NR_MAX_NOF_CORESET; ++cs_idx) {
if (cfg->cfg.pdcch.coreset_present[cs_idx]) { if (cfg->cfg.pdcch.coreset_present[cs_idx]) {
uint32_t cs_id = cfg->cfg.pdcch.coreset[cs_idx].id; uint32_t cs_id = cfg->cfg.pdcch.coreset[cs_idx].id;
coresets[cs_id].emplace(*cfg, cs_id, slot_idx_, dl_pdcchs, ul_pdcchs); coresets[cs_id].emplace(*cfg, cs_id, slot_idx_, dl.phy.pdcch_dl, dl.phy.pdcch_ul);
} }
} }
} }
@ -41,15 +41,15 @@ void bwp_slot_grid::reset()
} }
dl_prbs.reset(); dl_prbs.reset();
ul_prbs.reset(); ul_prbs.reset();
dl_pdcchs.clear(); dl.phy.ssb.clear();
ul_pdcchs.clear(); dl.phy.nzp_csi_rs.clear();
pdschs.clear(); dl.phy.pdcch_dl.clear();
puschs.clear(); dl.phy.pdcch_ul.clear();
dl.phy.pdsch.clear();
dl.rar.clear();
ul.pusch.clear();
ul.pucch.clear();
pending_acks.clear(); pending_acks.clear();
pucch.clear();
ssb.clear();
nzp_csi_rs.clear();
rar.clear();
} }
bwp_res_grid::bwp_res_grid(const bwp_params_t& bwp_cfg_) : cfg(&bwp_cfg_) bwp_res_grid::bwp_res_grid(const bwp_params_t& bwp_cfg_) : cfg(&bwp_cfg_)
@ -72,7 +72,7 @@ alloc_result bwp_slot_allocator::alloc_si(uint32_t aggr_idx, uint32_t si_idx, ui
logger.warning("SCHED: Trying to allocate PDSCH in TDD non-DL slot index=%d", bwp_pdcch_slot.slot_idx); logger.warning("SCHED: Trying to allocate PDSCH in TDD non-DL slot index=%d", bwp_pdcch_slot.slot_idx);
return alloc_result::no_sch_space; return alloc_result::no_sch_space;
} }
pdcch_dl_list_t& pdsch_grants = bwp_pdcch_slot.dl_pdcchs; pdcch_dl_list_t& pdsch_grants = bwp_pdcch_slot.dl.phy.pdcch_dl;
if (pdsch_grants.full()) { if (pdsch_grants.full()) {
logger.warning("SCHED: Maximum number of DL allocations reached"); logger.warning("SCHED: Maximum number of DL allocations reached");
return alloc_result::no_grant_space; return alloc_result::no_grant_space;
@ -104,7 +104,7 @@ alloc_result bwp_slot_allocator::alloc_rar_and_msg3(uint16_t
if (ret != alloc_result::success) { if (ret != alloc_result::success) {
return ret; return ret;
} }
if (pending_rachs.size() > bwp_pdcch_slot.rar.capacity() - bwp_pdcch_slot.rar.size()) { if (pending_rachs.size() > bwp_pdcch_slot.dl.rar.capacity() - bwp_pdcch_slot.dl.rar.size()) {
logger.error("SCHED: Trying to allocate too many Msg3 grants in a single slot (%zd)", pending_rachs.size()); logger.error("SCHED: Trying to allocate too many Msg3 grants in a single slot (%zd)", pending_rachs.size());
return alloc_result::invalid_grant_params; return alloc_result::invalid_grant_params;
} }
@ -144,7 +144,7 @@ alloc_result bwp_slot_allocator::alloc_rar_and_msg3(uint16_t
// RAR allocation successful. // RAR allocation successful.
bwp_pdcch_slot.dl_prbs |= interv; bwp_pdcch_slot.dl_prbs |= interv;
// Generate DCI for RAR with given RA-RNTI // Generate DCI for RAR with given RA-RNTI
pdcch_dl_t& pdcch = bwp_pdcch_slot.dl_pdcchs.back(); pdcch_dl_t& pdcch = bwp_pdcch_slot.dl.phy.pdcch_dl.back();
if (not fill_dci_rar(interv, ra_rnti, *bwp_grid.cfg, pdcch.dci)) { if (not fill_dci_rar(interv, ra_rnti, *bwp_grid.cfg, pdcch.dci)) {
// Cancel on-going PDCCH allocation // Cancel on-going PDCCH allocation
bwp_pdcch_slot.coresets[coreset_id]->rem_last_dci(); bwp_pdcch_slot.coresets[coreset_id]->rem_last_dci();
@ -154,8 +154,8 @@ alloc_result bwp_slot_allocator::alloc_rar_and_msg3(uint16_t
pdcch.dci_cfg = phy_cfg.get_dci_cfg(); pdcch.dci_cfg = phy_cfg.get_dci_cfg();
// Generate RAR PDSCH // Generate RAR PDSCH
// TODO: Properly fill Msg3 grants // TODO: Properly fill Msg3 grants
bwp_pdcch_slot.pdschs.emplace_back(); bwp_pdcch_slot.dl.phy.pdsch.emplace_back();
pdsch_t& pdsch = bwp_pdcch_slot.pdschs.back(); pdsch_t& pdsch = bwp_pdcch_slot.dl.phy.pdsch.back();
srsran_slot_cfg_t slot_cfg; srsran_slot_cfg_t slot_cfg;
slot_cfg.idx = pdcch_slot.to_uint(); slot_cfg.idx = pdcch_slot.to_uint();
bool success = phy_cfg.get_pdsch_cfg(slot_cfg, pdcch.dci, pdsch.sch); bool success = phy_cfg.get_pdsch_cfg(slot_cfg, pdcch.dci, pdsch.sch);
@ -166,8 +166,8 @@ alloc_result bwp_slot_allocator::alloc_rar_and_msg3(uint16_t
uint32_t last_msg3 = msg3_rbs.start(); uint32_t last_msg3 = msg3_rbs.start();
const int mcs = 0, max_harq_msg3_retx = 4; const int mcs = 0, max_harq_msg3_retx = 4;
slot_cfg.idx = msg3_slot.to_uint(); slot_cfg.idx = msg3_slot.to_uint();
bwp_pdcch_slot.rar.emplace_back(); bwp_pdcch_slot.dl.rar.emplace_back();
sched_nr_interface::rar_t& rar_out = bwp_pdcch_slot.rar.back(); sched_nr_interface::rar_t& rar_out = bwp_pdcch_slot.dl.rar.back();
for (const dl_sched_rar_info_t& grant : pending_rachs) { for (const dl_sched_rar_info_t& grant : pending_rachs) {
slot_ue& ue = slot_ues[grant.temp_crnti]; slot_ue& ue = slot_ues[grant.temp_crnti];
@ -183,8 +183,8 @@ alloc_result bwp_slot_allocator::alloc_rar_and_msg3(uint16_t
fill_dci_msg3(ue, *bwp_grid.cfg, rar_grant.msg3_dci); fill_dci_msg3(ue, *bwp_grid.cfg, rar_grant.msg3_dci);
// Generate PUSCH // Generate PUSCH
bwp_msg3_slot.puschs.emplace_back(); bwp_msg3_slot.ul.pusch.emplace_back();
pusch_t& pusch = bwp_msg3_slot.puschs.back(); pusch_t& pusch = bwp_msg3_slot.ul.pusch.back();
success = ue->phy().get_pusch_cfg(slot_cfg, rar_grant.msg3_dci, pusch.sch); success = ue->phy().get_pusch_cfg(slot_cfg, rar_grant.msg3_dci, pusch.sch);
srsran_assert(success, "Error converting DCI to PUSCH grant"); srsran_assert(success, "Error converting DCI to PUSCH grant");
pusch.sch.grant.tb[0].softbuffer.rx = ue.h_ul->get_softbuffer().get(); pusch.sch.grant.tb[0].softbuffer.rx = ue.h_ul->get_softbuffer().get();
@ -250,7 +250,7 @@ alloc_result bwp_slot_allocator::alloc_pdsch(slot_ue& ue, const prb_grant& dl_gr
const static float max_R = 0.93; const static float max_R = 0.93;
while (true) { while (true) {
// Generate PDCCH // Generate PDCCH
pdcch_dl_t& pdcch = bwp_pdcch_slot.dl_pdcchs.back(); pdcch_dl_t& pdcch = bwp_pdcch_slot.dl.phy.pdcch_dl.back();
fill_dl_dci_ue_fields(ue, *bwp_grid.cfg, ss_id, pdcch.dci.ctx.location, pdcch.dci); fill_dl_dci_ue_fields(ue, *bwp_grid.cfg, ss_id, pdcch.dci.ctx.location, pdcch.dci);
pdcch.dci.pucch_resource = 0; pdcch.dci.pucch_resource = 0;
pdcch.dci.dai = std::count_if(bwp_uci_slot.pending_acks.begin(), pdcch.dci.dai = std::count_if(bwp_uci_slot.pending_acks.begin(),
@ -267,8 +267,8 @@ alloc_result bwp_slot_allocator::alloc_pdsch(slot_ue& ue, const prb_grant& dl_gr
// Generate PDSCH // Generate PDSCH
bwp_pdsch_slot.dl_prbs |= dl_grant; bwp_pdsch_slot.dl_prbs |= dl_grant;
bwp_pdsch_slot.pdschs.emplace_back(); bwp_pdsch_slot.dl.phy.pdsch.emplace_back();
pdsch_t& pdsch = bwp_pdsch_slot.pdschs.back(); pdsch_t& pdsch = bwp_pdsch_slot.dl.phy.pdsch.back();
srsran_slot_cfg_t slot_cfg; srsran_slot_cfg_t slot_cfg;
slot_cfg.idx = ue.pdsch_slot.to_uint(); slot_cfg.idx = ue.pdsch_slot.to_uint();
bool ret = ue->phy().get_pdsch_cfg(slot_cfg, pdcch.dci, pdsch.sch); bool ret = ue->phy().get_pdsch_cfg(slot_cfg, pdcch.dci, pdsch.sch);
@ -281,13 +281,13 @@ alloc_result bwp_slot_allocator::alloc_pdsch(slot_ue& ue, const prb_grant& dl_gr
} else { } else {
srsran_assert(pdsch.sch.grant.tb[0].tbs == (int)ue.h_dl->tbs(), "The TBS did not remain constant in retx"); srsran_assert(pdsch.sch.grant.tb[0].tbs == (int)ue.h_dl->tbs(), "The TBS did not remain constant in retx");
} }
if (ue.h_dl->nof_retx() > 0 or bwp_pdsch_slot.pdschs.back().sch.grant.tb[0].R_prime < max_R or mcs <= 0) { if (ue.h_dl->nof_retx() > 0 or bwp_pdsch_slot.dl.phy.pdsch.back().sch.grant.tb[0].R_prime < max_R or mcs <= 0) {
break; break;
} }
// Decrease MCS if first tx and rate is too high // Decrease MCS if first tx and rate is too high
mcs--; mcs--;
ue.h_dl->set_mcs(mcs); ue.h_dl->set_mcs(mcs);
bwp_pdsch_slot.pdschs.pop_back(); bwp_pdsch_slot.dl.phy.pdsch.pop_back();
bwp_uci_slot.pending_acks.pop_back(); bwp_uci_slot.pending_acks.pop_back();
} }
if (mcs == 0) { if (mcs == 0) {
@ -309,7 +309,7 @@ alloc_result bwp_slot_allocator::alloc_pusch(slot_ue& ue, const prb_grant& ul_pr
if (ret != alloc_result::success) { if (ret != alloc_result::success) {
return ret; return ret;
} }
pdcch_ul_list_t& pdcchs = bwp_pdcch_slot.ul_pdcchs; pdcch_ul_list_t& pdcchs = bwp_pdcch_slot.dl.phy.pdcch_ul;
if (bwp_pusch_slot.ul_prbs.collides(ul_prbs)) { if (bwp_pusch_slot.ul_prbs.collides(ul_prbs)) {
return alloc_result::sch_collision; return alloc_result::sch_collision;
} }
@ -347,8 +347,8 @@ alloc_result bwp_slot_allocator::alloc_pusch(slot_ue& ue, const prb_grant& ul_pr
pdcch.dci_cfg = ue->phy().get_dci_cfg(); pdcch.dci_cfg = ue->phy().get_dci_cfg();
// Generate PUSCH // Generate PUSCH
bwp_pusch_slot.ul_prbs |= ul_prbs; bwp_pusch_slot.ul_prbs |= ul_prbs;
bwp_pusch_slot.puschs.emplace_back(); bwp_pusch_slot.ul.pusch.emplace_back();
pusch_t& pusch = bwp_pusch_slot.puschs.back(); pusch_t& pusch = bwp_pusch_slot.ul.pusch.back();
srsran_slot_cfg_t slot_cfg; srsran_slot_cfg_t slot_cfg;
slot_cfg.idx = ue.pusch_slot.to_uint(); slot_cfg.idx = ue.pusch_slot.to_uint();
pusch.pid = ue.h_ul->pid; pusch.pid = ue.h_ul->pid;
@ -372,11 +372,11 @@ alloc_result bwp_slot_allocator::verify_pdsch_space(bwp_slot_grid& pdsch_grid,
logger.warning("SCHED: Trying to allocate PDSCH in TDD non-DL slot index=%d", pdsch_grid.slot_idx); logger.warning("SCHED: Trying to allocate PDSCH in TDD non-DL slot index=%d", pdsch_grid.slot_idx);
return alloc_result::no_sch_space; return alloc_result::no_sch_space;
} }
if (pdcch_grid.dl_pdcchs.full()) { if (pdcch_grid.dl.phy.pdcch_dl.full()) {
logger.warning("SCHED: Maximum number of DL PDCCH allocations reached"); logger.warning("SCHED: Maximum number of DL PDCCH allocations reached");
return alloc_result::no_cch_space; return alloc_result::no_cch_space;
} }
if (pdsch_grid.pdschs.full()) { if (pdsch_grid.dl.phy.pdsch.full()) {
logger.warning("SCHED: Maximum number of DL PDSCH grants reached"); logger.warning("SCHED: Maximum number of DL PDSCH grants reached");
return alloc_result::no_sch_space; return alloc_result::no_sch_space;
} }
@ -386,7 +386,7 @@ alloc_result bwp_slot_allocator::verify_pdsch_space(bwp_slot_grid& pdsch_grid,
return alloc_result::no_grant_space; return alloc_result::no_grant_space;
} }
} }
if (not pdsch_grid.ssb.empty()) { if (not pdsch_grid.dl.phy.ssb.empty()) {
// TODO: support concurrent PDSCH and SSB // TODO: support concurrent PDSCH and SSB
logger.debug("SCHED: skipping PDSCH allocation. Cause: concurrent PDSCH and SSB not yet supported"); logger.debug("SCHED: skipping PDSCH allocation. Cause: concurrent PDSCH and SSB not yet supported");
return alloc_result::no_sch_space; return alloc_result::no_sch_space;
@ -406,12 +406,12 @@ alloc_result bwp_slot_allocator::verify_pusch_space(bwp_slot_grid& pusch_grid, b
logger.warning("SCHED: Trying to allocate PDCCH in TDD non-DL slot index=%d", pdcch_grid->slot_idx); logger.warning("SCHED: Trying to allocate PDCCH in TDD non-DL slot index=%d", pdcch_grid->slot_idx);
return alloc_result::no_sch_space; return alloc_result::no_sch_space;
} }
if (pdcch_grid->ul_pdcchs.full()) { if (pdcch_grid->dl.phy.pdcch_ul.full()) {
logger.warning("SCHED: Maximum number of PUSCH allocations reached"); logger.warning("SCHED: Maximum number of PUSCH allocations reached");
return alloc_result::no_grant_space; return alloc_result::no_grant_space;
} }
} }
if (pusch_grid.puschs.full()) { if (pusch_grid.ul.pusch.full()) {
logger.warning("SCHED: Maximum number of PUSCH allocations reached"); logger.warning("SCHED: Maximum number of PUSCH allocations reached");
return alloc_result::no_grant_space; return alloc_result::no_grant_space;
} }

@ -139,7 +139,7 @@ void log_sched_bwp_result(srslog::basic_logger& logger,
{ {
const bwp_slot_grid& bwp_slot = res_grid[pdcch_slot]; const bwp_slot_grid& bwp_slot = res_grid[pdcch_slot];
size_t rar_count = 0; size_t rar_count = 0;
for (const pdcch_dl_t& pdcch : bwp_slot.dl_pdcchs) { for (const pdcch_dl_t& pdcch : bwp_slot.dl.phy.pdcch_dl) {
fmt::memory_buffer fmtbuf; fmt::memory_buffer fmtbuf;
if (pdcch.dci.ctx.rnti_type == srsran_rnti_type_c) { if (pdcch.dci.ctx.rnti_type == srsran_rnti_type_c) {
const slot_ue& ue = slot_ues[pdcch.dci.ctx.rnti]; const slot_ue& ue = slot_ues[pdcch.dci.ctx.rnti];
@ -160,7 +160,7 @@ void log_sched_bwp_result(srslog::basic_logger& logger,
ue.pdsch_slot, ue.pdsch_slot,
ue.uci_slot); ue.uci_slot);
} else if (pdcch.dci.ctx.rnti_type == srsran_rnti_type_ra) { } else if (pdcch.dci.ctx.rnti_type == srsran_rnti_type_ra) {
const pdsch_t& pdsch = bwp_slot.pdschs[std::distance(bwp_slot.dl_pdcchs.data(), &pdcch)]; const pdsch_t& pdsch = bwp_slot.dl.phy.pdsch[std::distance(bwp_slot.dl.phy.pdcch_dl.data(), &pdcch)];
srsran::const_span<bool> prbs{pdsch.sch.grant.prb_idx, pdsch.sch.grant.prb_idx + pdsch.sch.grant.nof_prb}; srsran::const_span<bool> prbs{pdsch.sch.grant.prb_idx, pdsch.sch.grant.prb_idx + pdsch.sch.grant.nof_prb};
uint32_t start_idx = std::distance(prbs.begin(), std::find(prbs.begin(), prbs.end(), true)); uint32_t start_idx = std::distance(prbs.begin(), std::find(prbs.begin(), prbs.end(), true));
uint32_t end_idx = std::distance(prbs.begin(), std::find(prbs.begin() + start_idx, prbs.end(), false)); uint32_t end_idx = std::distance(prbs.begin(), std::find(prbs.begin() + start_idx, prbs.end(), false));
@ -171,7 +171,7 @@ void log_sched_bwp_result(srslog::basic_logger& logger,
srsran::interval<uint32_t>{start_idx, end_idx}, srsran::interval<uint32_t>{start_idx, end_idx},
pdcch_slot, pdcch_slot,
pdcch_slot + res_grid.cfg->pusch_ra_list[0].msg3_delay, pdcch_slot + res_grid.cfg->pusch_ra_list[0].msg3_delay,
bwp_slot.rar[rar_count].grants.size()); bwp_slot.dl.rar[rar_count].grants.size());
rar_count++; rar_count++;
} else { } else {
fmt::format_to(fmtbuf, "SCHED: unknown format"); fmt::format_to(fmtbuf, "SCHED: unknown format");
@ -179,7 +179,7 @@ void log_sched_bwp_result(srslog::basic_logger& logger,
logger.info("%s", srsran::to_c_str(fmtbuf)); logger.info("%s", srsran::to_c_str(fmtbuf));
} }
for (const pdcch_ul_t& pdcch : bwp_slot.ul_pdcchs) { for (const pdcch_ul_t& pdcch : bwp_slot.dl.phy.pdcch_ul) {
fmt::memory_buffer fmtbuf; fmt::memory_buffer fmtbuf;
if (pdcch.dci.ctx.rnti_type == srsran_rnti_type_c) { if (pdcch.dci.ctx.rnti_type == srsran_rnti_type_c) {
const slot_ue& ue = slot_ues[pdcch.dci.ctx.rnti]; const slot_ue& ue = slot_ues[pdcch.dci.ctx.rnti];

@ -29,33 +29,21 @@ cc_worker::cc_worker(const cell_params_t& params) :
harq_softbuffer_pool::get_instance().init_pool(cfg.nof_prb()); harq_softbuffer_pool::get_instance().init_pool(cfg.nof_prb());
} }
bool cc_worker::save_sched_result(dl_sched_res_t& dl_res, ul_sched_t& ul_res, slot_point slot_tx)
{
auto& bwp_slot = bwps[0].grid[slot_tx];
dl_res.dl_sched.pdcch_dl = bwp_slot.dl_pdcchs;
dl_res.dl_sched.pdcch_ul = bwp_slot.ul_pdcchs;
dl_res.dl_sched.pdsch = bwp_slot.pdschs;
dl_res.rar = bwp_slot.rar;
dl_res.dl_sched.ssb = bwp_slot.ssb;
dl_res.dl_sched.nzp_csi_rs = bwp_slot.nzp_csi_rs;
ul_res.pusch = bwp_slot.puschs;
ul_res.pucch = bwp_slot.pucch;
// clear up BWP slot
bwp_slot.reset();
return true;
}
void cc_worker::dl_rach_info(const sched_nr_interface::rar_info_t& rar_info) void cc_worker::dl_rach_info(const sched_nr_interface::rar_info_t& rar_info)
{ {
bwps[0].ra.dl_rach_info(rar_info); bwps[0].ra.dl_rach_info(rar_info);
} }
/// Called within a locked context, to generate {slot, cc} scheduling decision /// Called within a locked context, to generate {slot, cc} scheduling decision
void cc_worker::run_slot(slot_point pdcch_slot, ue_map_t& ue_db, dl_sched_res_t& dl_res, ul_sched_t& ul_res)
dl_sched_res_t* cc_worker::run_slot(slot_point pdcch_slot, ue_map_t& ue_db)
{ {
// Reset old sched outputs
slot_point old_slot = pdcch_slot - TX_ENB_DELAY - 1;
for (bwp_manager& bwp : bwps) {
bwp.grid[old_slot].reset();
}
// Reserve UEs for this worker slot (select candidate UEs) // Reserve UEs for this worker slot (select candidate UEs)
for (auto& ue_pair : ue_db) { for (auto& ue_pair : ue_db) {
uint16_t rnti = ue_pair.first; uint16_t rnti = ue_pair.first;
@ -82,7 +70,7 @@ void cc_worker::run_slot(slot_point pdcch_slot, ue_map_t& ue_db, dl_sched_res_t&
// Allocate cell DL signalling // Allocate cell DL signalling
bwp_slot_grid& bwp_pdcch_slot = bwps[0].grid[pdcch_slot]; bwp_slot_grid& bwp_pdcch_slot = bwps[0].grid[pdcch_slot];
sched_dl_signalling(*bwps[0].cfg, pdcch_slot, bwp_pdcch_slot.ssb, bwp_pdcch_slot.nzp_csi_rs); sched_dl_signalling(*bwps[0].cfg, pdcch_slot, bwp_pdcch_slot.dl.phy.ssb, bwp_pdcch_slot.dl.phy.nzp_csi_rs);
// Allocate pending RARs // Allocate pending RARs
bwps[0].ra.run_slot(bwp_alloc); bwps[0].ra.run_slot(bwp_alloc);
@ -97,11 +85,15 @@ void cc_worker::run_slot(slot_point pdcch_slot, ue_map_t& ue_db, dl_sched_res_t&
// Log CC scheduler result // Log CC scheduler result
log_sched_bwp_result(logger, bwp_alloc.get_pdcch_tti(), bwps[0].grid, slot_ues); log_sched_bwp_result(logger, bwp_alloc.get_pdcch_tti(), bwps[0].grid, slot_ues);
// Post-process and copy results to intermediate buffer
save_sched_result(dl_res, ul_res, pdcch_slot);
// releases UE resources // releases UE resources
slot_ues.clear(); slot_ues.clear();
return &bwp_pdcch_slot.dl;
}
ul_sched_t* cc_worker::get_ul_sched(slot_point sl)
{
return &bwps[0].grid[sl].ul;
} }
void cc_worker::alloc_dl_ues(bwp_slot_allocator& bwp_alloc) void cc_worker::alloc_dl_ues(bwp_slot_allocator& bwp_alloc)
@ -153,7 +145,7 @@ void cc_worker::postprocess_decisions(bwp_slot_allocator& bwp_alloc)
} }
bool has_pusch = false; bool has_pusch = false;
for (auto& pusch : bwp_slot.puschs) { for (auto& pusch : bwp_slot.ul.pusch) {
if (pusch.sch.grant.rnti == ue->rnti) { if (pusch.sch.grant.rnti == ue->rnti) {
// Put UCI configuration in PUSCH config // Put UCI configuration in PUSCH config
has_pusch = true; has_pusch = true;
@ -170,12 +162,12 @@ void cc_worker::postprocess_decisions(bwp_slot_allocator& bwp_alloc)
} }
if (not has_pusch) { if (not has_pusch) {
// If any UCI information is triggered, schedule PUCCH // If any UCI information is triggered, schedule PUCCH
if (bwp_slot.pucch.full()) { if (bwp_slot.ul.pucch.full()) {
logger.warning("SCHED: Cannot fit pending UCI into PUCCH"); logger.warning("SCHED: Cannot fit pending UCI into PUCCH");
continue; continue;
} }
bwp_slot.pucch.emplace_back(); bwp_slot.ul.pucch.emplace_back();
mac_interface_phy_nr::pucch_t& pucch = bwp_slot.pucch.back(); mac_interface_phy_nr::pucch_t& pucch = bwp_slot.ul.pucch.back();
uci_cfg.pucch.rnti = ue->rnti; uci_cfg.pucch.rnti = ue->rnti;
pucch.candidates.emplace_back(); pucch.candidates.emplace_back();

@ -55,7 +55,14 @@ void test_single_prach()
const bwp_slot_grid* result = nullptr; const bwp_slot_grid* result = nullptr;
auto run_slot = [&res_grid, &rasched, &pdcch_slot, &slot_ues, &u]() -> const bwp_slot_grid* { auto run_slot = [&res_grid, &rasched, &pdcch_slot, &slot_ues, &u]() -> const bwp_slot_grid* {
mac_logger.set_context(pdcch_slot.to_uint()); mac_logger.set_context(pdcch_slot.to_uint());
// delete old outputs
(*res_grid)[pdcch_slot - TX_ENB_DELAY - 1].reset();
// setup UE state for slot
u.new_slot(pdcch_slot); u.new_slot(pdcch_slot);
// pre-calculate UE slot vars
slot_ues.clear(); slot_ues.clear();
slot_ue sfu = u.make_slot_ue(pdcch_slot, 0); slot_ue sfu = u.make_slot_ue(pdcch_slot, 0);
if (not sfu.empty()) { if (not sfu.empty()) {
@ -67,7 +74,7 @@ void test_single_prach()
log_sched_bwp_result(mac_logger, alloc.get_pdcch_tti(), alloc.res_grid(), slot_ues); log_sched_bwp_result(mac_logger, alloc.get_pdcch_tti(), alloc.res_grid(), slot_ues);
const bwp_slot_grid* result = &alloc.res_grid()[alloc.get_pdcch_tti()]; const bwp_slot_grid* result = &alloc.res_grid()[alloc.get_pdcch_tti()];
test_dl_pdcch_consistency(result->dl_pdcchs); test_dl_pdcch_consistency(result->dl.phy.pdcch_dl);
++pdcch_slot; ++pdcch_slot;
return result; return result;
}; };
@ -76,7 +83,7 @@ void test_single_prach()
for (; pdcch_slot - TX_ENB_DELAY < prach_slot;) { for (; pdcch_slot - TX_ENB_DELAY < prach_slot;) {
result = run_slot(); result = run_slot();
TESTASSERT(result->dl_pdcchs.empty()); TESTASSERT(result->dl.phy.pdcch_dl.empty());
} }
// A PRACH arrives... // A PRACH arrives...
@ -97,15 +104,15 @@ void test_single_prach()
result = run_slot(); result = run_slot();
if (bwpparams.slots[current_slot.slot_idx()].is_dl and if (bwpparams.slots[current_slot.slot_idx()].is_dl and
bwpparams.slots[(current_slot + bwpparams.pusch_ra_list[0].msg3_delay).slot_idx()].is_ul) { bwpparams.slots[(current_slot + bwpparams.pusch_ra_list[0].msg3_delay).slot_idx()].is_ul) {
TESTASSERT_EQ(result->dl_pdcchs.size(), 1); TESTASSERT_EQ(result->dl.phy.pdcch_dl.size(), 1);
const auto& pdcch = result->dl_pdcchs[0]; const auto& pdcch = result->dl.phy.pdcch_dl[0];
TESTASSERT_EQ(pdcch.dci.ctx.rnti, ra_rnti); TESTASSERT_EQ(pdcch.dci.ctx.rnti, ra_rnti);
TESTASSERT_EQ(pdcch.dci.ctx.rnti_type, srsran_rnti_type_ra); TESTASSERT_EQ(pdcch.dci.ctx.rnti_type, srsran_rnti_type_ra);
TESTASSERT(current_slot < prach_slot + prach_duration + bwpparams.cfg.rar_window_size); TESTASSERT(current_slot < prach_slot + prach_duration + bwpparams.cfg.rar_window_size);
rar_slot = current_slot; rar_slot = current_slot;
break; break;
} else { } else {
TESTASSERT(result->dl_pdcchs.empty()); TESTASSERT(result->dl.phy.pdcch_dl.empty());
} }
} }
@ -113,7 +120,7 @@ void test_single_prach()
while (pdcch_slot <= msg3_slot) { while (pdcch_slot <= msg3_slot) {
result = run_slot(); result = run_slot();
} }
TESTASSERT(result->puschs.size() == 1); TESTASSERT(result->ul.pusch.size() == 1);
} }
} // namespace srsenb } // namespace srsenb

@ -42,8 +42,8 @@ int sched_nr_ue_sim::update(const sched_nr_cc_result_view& cc_out)
{ {
update_dl_harqs(cc_out); update_dl_harqs(cc_out);
for (uint32_t i = 0; i < cc_out.dl_cc_result.dl_sched.pdcch_dl.size(); ++i) { for (uint32_t i = 0; i < cc_out.dl->phy.pdcch_dl.size(); ++i) {
const auto& data = cc_out.dl_cc_result.dl_sched.pdcch_dl[i]; const auto& data = cc_out.dl->phy.pdcch_dl[i];
if (data.dci.ctx.rnti != ctxt.rnti) { if (data.dci.ctx.rnti != ctxt.rnti) {
continue; continue;
} }
@ -64,8 +64,8 @@ int sched_nr_ue_sim::update(const sched_nr_cc_result_view& cc_out)
void sched_nr_ue_sim::update_dl_harqs(const sched_nr_cc_result_view& cc_out) void sched_nr_ue_sim::update_dl_harqs(const sched_nr_cc_result_view& cc_out)
{ {
uint32_t cc = cc_out.cc; uint32_t cc = cc_out.cc;
for (uint32_t i = 0; i < cc_out.dl_cc_result.dl_sched.pdcch_dl.size(); ++i) { for (uint32_t i = 0; i < cc_out.dl->phy.pdcch_dl.size(); ++i) {
const auto& data = cc_out.dl_cc_result.dl_sched.pdcch_dl[i]; const auto& data = cc_out.dl->phy.pdcch_dl[i];
if (data.dci.ctx.rnti != ctxt.rnti) { if (data.dci.ctx.rnti != ctxt.rnti) {
continue; continue;
} }
@ -208,10 +208,10 @@ void sched_nr_base_tester::run_slot(slot_point slot_tx)
void sched_nr_base_tester::generate_cc_result(uint32_t cc) void sched_nr_base_tester::generate_cc_result(uint32_t cc)
{ {
// Run scheduler // Run scheduler
sched_nr_interface::dl_res_t dl_sched(cc_results[cc].rar, cc_results[cc].dl_res); cc_results[cc].res.slot = current_slot_tx;
sched_ptr->get_dl_sched(current_slot_tx, cc, dl_sched); cc_results[cc].res.cc = cc;
cc_results[cc].rar = dl_sched.rar; cc_results[cc].res.dl = sched_ptr->get_dl_sched(current_slot_tx, cc);
sched_ptr->get_ul_sched(current_slot_tx, cc, cc_results[cc].ul_res); cc_results[cc].res.ul = sched_ptr->get_ul_sched(current_slot_tx, cc);
auto tp2 = std::chrono::steady_clock::now(); auto tp2 = std::chrono::steady_clock::now();
cc_results[cc].cc_latency_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(tp2 - slot_start_tp); cc_results[cc].cc_latency_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(tp2 - slot_start_tp);
@ -233,13 +233,12 @@ void sched_nr_base_tester::process_results()
process_slot_result(slot_ctxt, cc_results); process_slot_result(slot_ctxt, cc_results);
for (uint32_t cc = 0; cc < cell_params.size(); ++cc) { for (uint32_t cc = 0; cc < cell_params.size(); ++cc) {
sched_nr_cc_result_view cc_out{ sched_nr_cc_result_view cc_out = cc_results[cc].res;
current_slot_tx, cc, cc_results[cc].rar, cc_results[cc].dl_res, cc_results[cc].ul_res};
// Run common tests // Run common tests
test_dl_pdcch_consistency(cc_out.dl_cc_result.dl_sched.pdcch_dl); test_dl_pdcch_consistency(cc_out.dl->phy.pdcch_dl);
test_pdsch_consistency(cc_out.dl_cc_result.dl_sched.pdsch); test_pdsch_consistency(cc_out.dl->phy.pdsch);
test_ssb_scheduled_grant(cc_out.slot, cell_params[cc_out.cc].cfg, cc_out.dl_cc_result.dl_sched.ssb); test_ssb_scheduled_grant(cc_out.slot, cell_params[cc_out.cc].cfg, cc_out.dl->phy.ssb);
// Run UE-dedicated tests // Run UE-dedicated tests
test_dl_sched_result(slot_ctxt, cc_out); test_dl_sched_result(slot_ctxt, cc_out);

@ -40,17 +40,9 @@ struct ue_nr_harq_ctxt_t {
}; };
struct sched_nr_cc_result_view { struct sched_nr_cc_result_view {
slot_point slot; slot_point slot;
uint32_t cc; uint32_t cc = 0;
const sched_nr_interface::dl_res_t dl_cc_result; const sched_nr_interface::dl_res_t* dl = nullptr;
const sched_nr_interface::ul_res_t* ul_cc_result; const sched_nr_interface::ul_res_t* ul = nullptr;
sched_nr_cc_result_view(slot_point slot_,
uint32_t cc_,
sched_nr_interface::sched_rar_list_t& rar,
sched_nr_interface::dl_sched_t& dl_res,
sched_nr_interface::ul_res_t& ul_res) :
slot(slot_), cc(cc_), dl_cc_result(rar, dl_res), ul_cc_result(&ul_res)
{}
}; };
struct ue_nr_cc_ctxt_t { struct ue_nr_cc_ctxt_t {
@ -116,11 +108,7 @@ class sched_nr_base_tester
{ {
public: public:
struct cc_result_t { struct cc_result_t {
slot_point slot_tx; sched_nr_cc_result_view res;
uint32_t cc;
sched_nr_interface::dl_sched_t dl_res;
sched_nr_interface::sched_rar_list_t rar;
sched_nr_interface::ul_res_t ul_res;
std::chrono::nanoseconds cc_latency_ns; std::chrono::nanoseconds cc_latency_ns;
}; };

@ -36,16 +36,16 @@ public:
})->cc_latency_ns.count(); })->cc_latency_ns.count();
for (auto& cc_out : cc_list) { for (auto& cc_out : cc_list) {
pdsch_count += cc_out.dl_res.pdcch_dl.size(); pdsch_count += cc_out.res.dl->phy.pdcch_dl.size();
cc_res_count++; cc_res_count++;
bool is_dl_slot = srsran_duplex_nr_is_dl(&cell_params[cc_out.cc].cfg.duplex, 0, current_slot_tx.slot_idx()); bool is_dl_slot = srsran_duplex_nr_is_dl(&cell_params[cc_out.res.cc].cfg.duplex, 0, current_slot_tx.slot_idx());
if (is_dl_slot) { if (is_dl_slot) {
if (cc_out.dl_res.ssb.empty()) { if (cc_out.res.dl->phy.ssb.empty()) {
TESTASSERT(slot_ctxt.ue_db.empty() or cc_out.dl_res.pdcch_dl.size() == 1); TESTASSERT(slot_ctxt.ue_db.empty() or cc_out.res.dl->phy.pdcch_dl.size() == 1);
} else { } else {
TESTASSERT(cc_out.dl_res.pdcch_dl.size() == 0); TESTASSERT(cc_out.res.dl->phy.pdcch_dl.size() == 0);
} }
} }
} }

@ -21,7 +21,7 @@ using namespace srsenb::sched_nr_impl;
void test_dl_sched_result(const sim_nr_enb_ctxt_t& enb_ctxt, const sched_nr_cc_result_view& cc_out) void test_dl_sched_result(const sim_nr_enb_ctxt_t& enb_ctxt, const sched_nr_cc_result_view& cc_out)
{ {
slot_point pdcch_slot = cc_out.slot; slot_point pdcch_slot = cc_out.slot;
const pdcch_dl_list_t& pdcchs = cc_out.dl_cc_result.dl_sched.pdcch_dl; const pdcch_dl_list_t& pdcchs = cc_out.dl->phy.pdcch_dl;
// Iterate over UE PDCCH allocations // Iterate over UE PDCCH allocations
for (const pdcch_dl_t& pdcch : pdcchs) { for (const pdcch_dl_t& pdcch : pdcchs) {

@ -465,7 +465,7 @@ public:
int slot_indication(const srsran_slot_cfg_t& slot_cfg) override { return 0; } int slot_indication(const srsran_slot_cfg_t& slot_cfg) override { return 0; }
int get_dl_sched(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) override dl_sched_t* get_dl_sched(const srsran_slot_cfg_t& slot_cfg) override
{ {
logger.set_context(slot_cfg.idx); logger.set_context(slot_cfg.idx);
sched_logger.set_context(slot_cfg.idx); sched_logger.set_context(slot_cfg.idx);
@ -476,36 +476,41 @@ public:
mac->ul_bsr(rnti, 0, 100000); mac->ul_bsr(rnti, 0, 100000);
} }
int ret = mac->get_dl_sched(slot_cfg, dl_sched); dl_sched_t* dl_res = mac->get_dl_sched(slot_cfg);
if (dl_res == nullptr) {
return nullptr;
}
for (pdsch_t& pdsch : dl_sched.pdsch) { for (pdsch_t& pdsch : dl_res->pdsch) {
// Set TBS // Set TBS
// Select grant and set data // Select grant and set data
pdsch.data[0] = tx_harq_proc[slot_cfg.idx].get_tb(pdsch.sch.grant.tb[0].tbs); pdsch.data[0] = tx_harq_proc[slot_cfg.idx].get_tb(pdsch.sch.grant.tb[0].tbs);
pdsch.data[1] = nullptr; pdsch.data[1] = nullptr;
} }
return ret; return dl_res;
} }
dl_sched_t& dl_sched = dl_scheds[slot_cfg.idx];
dl_sched = {};
// Check if it is TDD DL slot and PDSCH mask, if no PDSCH shall be scheduled, do not set any grant and skip // Check if it is TDD DL slot and PDSCH mask, if no PDSCH shall be scheduled, do not set any grant and skip
if (not srsran_duplex_nr_is_dl(&phy_cfg.duplex, phy_cfg.carrier.scs, slot_cfg.idx)) { if (not srsran_duplex_nr_is_dl(&phy_cfg.duplex, phy_cfg.carrier.scs, slot_cfg.idx)) {
return SRSRAN_SUCCESS; return nullptr;
} }
if (not schedule_pdsch(slot_cfg, dl_sched)) { if (not schedule_pdsch(slot_cfg, dl_sched)) {
logger.error("Error scheduling PDSCH"); logger.error("Error scheduling PDSCH");
return SRSRAN_ERROR; return nullptr;
} }
// Check if the UL slot is valid, if not skip UL scheduling // Check if the UL slot is valid, if not skip UL scheduling
if (not srsran_duplex_nr_is_ul(&phy_cfg.duplex, phy_cfg.carrier.scs, TTI_TX(slot_cfg.idx))) { if (not srsran_duplex_nr_is_ul(&phy_cfg.duplex, phy_cfg.carrier.scs, TTI_TX(slot_cfg.idx))) {
return SRSRAN_SUCCESS; return &dl_sched;
} }
if (not schedule_pusch(slot_cfg, dl_sched)) { if (not schedule_pusch(slot_cfg, dl_sched)) {
logger.error("Error scheduling PUSCH"); logger.error("Error scheduling PUSCH");
return SRSRAN_ERROR; return nullptr;
} }
// Schedule NZP-CSI-RS, iterate all NZP-CSI-RS sets // Schedule NZP-CSI-RS, iterate all NZP-CSI-RS sets
@ -541,19 +546,21 @@ public:
} }
} }
return SRSRAN_SUCCESS; return &dl_sched;
} }
int get_ul_sched(const srsran_slot_cfg_t& slot_cfg, ul_sched_t& ul_sched) override ul_sched_t* get_ul_sched(const srsran_slot_cfg_t& slot_cfg) override
{ {
logger.set_context(slot_cfg.idx); logger.set_context(slot_cfg.idx);
sched_logger.set_context(slot_cfg.idx); sched_logger.set_context(slot_cfg.idx);
if (not use_dummy_mac) { if (not use_dummy_mac) {
int ret = mac->get_ul_sched(slot_cfg, ul_sched); ul_sched_t* ul_res = mac->get_ul_sched(slot_cfg);
return ul_res;
return ret;
} }
ul_sched_t& ul_sched = ul_scheds[slot_cfg.idx];
ul_sched.pucch.clear();
ul_sched.pusch.clear();
// Get ACK information // Get ACK information
srsran_pdsch_ack_nr_t ack = pending_ack[slot_cfg.idx % pending_ack.size()].get_ack(); srsran_pdsch_ack_nr_t ack = pending_ack[slot_cfg.idx % pending_ack.size()].get_ack();
@ -573,7 +580,7 @@ public:
srsran_uci_cfg_nr_t uci_cfg = {}; srsran_uci_cfg_nr_t uci_cfg = {};
if (not phy_cfg.get_uci_cfg(slot_cfg, ack, uci_cfg)) { if (not phy_cfg.get_uci_cfg(slot_cfg, ack, uci_cfg)) {
logger.error("Error getting UCI configuration"); logger.error("Error getting UCI configuration");
return SRSRAN_ERROR; return nullptr;
} }
// Schedule PUSCH // Schedule PUSCH
@ -584,15 +591,12 @@ public:
// Put UCI configuration in PUSCH config // Put UCI configuration in PUSCH config
if (not phy_cfg.get_pusch_uci_cfg(slot_cfg, uci_cfg, pusch.sch)) { if (not phy_cfg.get_pusch_uci_cfg(slot_cfg, uci_cfg, pusch.sch)) {
logger.error("Error setting UCI configuration in PUSCH"); logger.error("Error setting UCI configuration in PUSCH");
return SRSRAN_ERROR; return nullptr;
} }
ul_sched.pusch.push_back(pusch); ul_sched.pusch.push_back(pusch);
return SRSRAN_SUCCESS; } else if (uci_cfg.ack.count > 0 || uci_cfg.nof_csi > 0 || uci_cfg.o_sr > 0) {
}
// If any UCI information is triggered, schedule PUCCH // If any UCI information is triggered, schedule PUCCH
if (uci_cfg.ack.count > 0 || uci_cfg.nof_csi > 0 || uci_cfg.o_sr > 0) {
ul_sched.pucch.emplace_back(); ul_sched.pucch.emplace_back();
uci_cfg.pucch.rnti = rnti; uci_cfg.pucch.rnti = rnti;
@ -602,7 +606,7 @@ public:
pucch.candidates.back().uci_cfg = uci_cfg; pucch.candidates.back().uci_cfg = uci_cfg;
if (not phy_cfg.get_pucch_uci_cfg(slot_cfg, uci_cfg, pucch.pucch_cfg, pucch.candidates.back().resource)) { if (not phy_cfg.get_pucch_uci_cfg(slot_cfg, uci_cfg, pucch.pucch_cfg, pucch.candidates.back().resource)) {
logger.error("Error getting UCI CFG"); logger.error("Error getting UCI CFG");
return SRSRAN_ERROR; return nullptr;
} }
// If this slot has a SR opportunity and the selected PUCCH format is 1, consider positive SR. // If this slot has a SR opportunity and the selected PUCCH format is 1, consider positive SR.
@ -618,15 +622,12 @@ public:
pucch.candidates.back().uci_cfg = uci_cfg; pucch.candidates.back().uci_cfg = uci_cfg;
if (not phy_cfg.get_pucch_uci_cfg(slot_cfg, uci_cfg, pucch.pucch_cfg, pucch.candidates.back().resource)) { if (not phy_cfg.get_pucch_uci_cfg(slot_cfg, uci_cfg, pucch.pucch_cfg, pucch.candidates.back().resource)) {
logger.error("Error getting UCI CFG"); logger.error("Error getting UCI CFG");
return SRSRAN_ERROR; return nullptr;
} }
} }
return SRSRAN_SUCCESS;
} }
// Otherwise no UL scheduling return &ul_sched;
return SRSRAN_SUCCESS;
} }
int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override
@ -728,6 +729,10 @@ public:
} }
return metrics; return metrics;
} }
private:
srsran::circular_array<dl_sched_t, TTIMOD_SZ> dl_scheds;
srsran::circular_array<ul_sched_t, TTIMOD_SZ> ul_scheds;
}; };
#endif // SRSRAN_DUMMY_GNB_STACK_H #endif // SRSRAN_DUMMY_GNB_STACK_H

Loading…
Cancel
Save