diff --git a/srsenb/hdr/stack/mac/scheduler.h b/srsenb/hdr/stack/mac/scheduler.h index a0c7b09bc..5a496f6ca 100644 --- a/srsenb/hdr/stack/mac/scheduler.h +++ b/srsenb/hdr/stack/mac/scheduler.h @@ -153,6 +153,7 @@ protected: uint32_t window_start; uint32_t n_tx; } sched_sib_t; + class bc_sched_t; class tti_sched_t : public dl_tti_sched_t, public ul_tti_sched_t { diff --git a/srsenb/hdr/stack/mac/scheduler_ctrl.h b/srsenb/hdr/stack/mac/scheduler_ctrl.h new file mode 100644 index 000000000..94f243680 --- /dev/null +++ b/srsenb/hdr/stack/mac/scheduler_ctrl.h @@ -0,0 +1,60 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE 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. + * + * srsLTE 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/. + * + */ + +#ifndef SRSLTE_SCHEDULER_CTRL_H +#define SRSLTE_SCHEDULER_CTRL_H + +#include "scheduler.h" + +namespace srsenb { + +class sched::bc_sched_t +{ +public: + bc_sched_t(cell_cfg_t* cfg_); + + void dl_sched(tti_sched_t* tti_sched); + void reset(); + +private: + struct sched_sib_t { + bool is_in_window = false; + uint32_t window_start = 0; + uint32_t n_tx = 0; + }; + + void update_si_windows(tti_sched_t* tti_sched); + void alloc_sibs(tti_sched_t* tti_sched); + + // args + cell_cfg_t* cfg; + + std::array pending_sibs; + + // TTI specific + uint32_t current_sfn = 0, current_sf_idx = 0; + uint32_t current_tti = 0; + uint32_t bc_aggr_level = 2; +}; + +} // namespace srsenb + +#endif // SRSLTE_SCHEDULER_CTRL_H diff --git a/srsenb/hdr/stack/mac/scheduler_grid.h b/srsenb/hdr/stack/mac/scheduler_grid.h index e65af20fd..8156058e8 100644 --- a/srsenb/hdr/stack/mac/scheduler_grid.h +++ b/srsenb/hdr/stack/mac/scheduler_grid.h @@ -100,7 +100,7 @@ private: size_t nof_dci_allocs = 0; }; -//! manages a full TTI grid, namely CCE and RB allocations +//! manages a full TTI grid resources, namely CCE and DL/UL RB allocations class tti_grid_t { public: diff --git a/srsenb/src/stack/mac/scheduler_ctrl.cc b/srsenb/src/stack/mac/scheduler_ctrl.cc new file mode 100644 index 000000000..e7a496fdb --- /dev/null +++ b/srsenb/src/stack/mac/scheduler_ctrl.cc @@ -0,0 +1,109 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE 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. + * + * srsLTE 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/. + * + */ + +#include "srsenb/hdr/stack/mac/scheduler_ctrl.h" + +namespace srsenb { + +sched::bc_sched_t::bc_sched_t(cell_cfg_t* cfg_) : cfg(cfg_) {} + +void sched::bc_sched_t::dl_sched(sched::tti_sched_t* tti_sched) +{ + current_sf_idx = tti_sched->get_sf_idx(); + current_sfn = tti_sched->get_sfn(); + current_tti = tti_sched->get_tti_tx_dl(); + bc_aggr_level = 2; + + /* Activate/deactivate SI windows */ + update_si_windows(tti_sched); + + /* Allocate DCIs and RBGs for each SIB */ + alloc_sibs(tti_sched); +} + +void sched::bc_sched_t::update_si_windows(tti_sched_t* tti_sched) +{ + uint32_t tti_tx_dl = tti_sched->get_tti_tx_dl(); + + for (uint32_t i = 0; i < pending_sibs.size(); ++i) { + // There is SIB data + if (cfg->sibs[i].len == 0) { + continue; + } + + if (not pending_sibs[i].is_in_window) { + uint32_t sf = 5; + uint32_t x = 0; + if (i > 0) { + x = (i - 1) * cfg->si_window_ms; + sf = x % 10; + } + if ((current_sfn % (cfg->sibs[i].period_rf)) == x / 10 && current_sf_idx == sf) { + pending_sibs[i].is_in_window = true; + pending_sibs[i].window_start = tti_tx_dl; + pending_sibs[i].n_tx = 0; + } + } else { + if (i > 0) { + if (srslte_tti_interval(tti_tx_dl, pending_sibs[i].window_start) > cfg->si_window_ms) { + // the si window has passed + pending_sibs[i] = {}; + } + } else { + // SIB1 is always in window + if (pending_sibs[0].n_tx == 4) { + pending_sibs[0].n_tx = 0; + } + } + } + } +} + +void sched::bc_sched_t::alloc_sibs(tti_sched_t* tti_sched) +{ + for (uint32_t i = 0; i < pending_sibs.size(); i++) { + if (cfg->sibs[i].len > 0 and pending_sibs[i].is_in_window and pending_sibs[i].n_tx < 4) { + uint32_t nof_tx = (i > 0) ? SRSLTE_MIN(srslte::ceil_div(cfg->si_window_ms, 10), 4) : 4; + uint32_t n_sf = (tti_sched->get_tti_tx_dl() - pending_sibs[i].window_start); + + // Check if there is any SIB to tx + bool sib1_flag = (i == 0) and (current_sfn % 2) == 0 and current_sf_idx == 5; + bool other_sibs_flag = + (i > 0) and (n_sf >= (cfg->si_window_ms / nof_tx) * pending_sibs[i].n_tx) and current_sf_idx == 9; + if (not sib1_flag and not other_sibs_flag) { + continue; + } + + // Schedule SIB + tti_sched->alloc_bc(bc_aggr_level, i, pending_sibs[i].n_tx); + pending_sibs[i].n_tx++; + } + } +} + +void sched::bc_sched_t::reset() +{ + for (auto& sib : pending_sibs) { + sib = {}; + } +} + +} // namespace srsenb diff --git a/srsenb/src/stack/mac/scheduler_grid.cc b/srsenb/src/stack/mac/scheduler_grid.cc index 67c763f97..4d62e5d4d 100644 --- a/srsenb/src/stack/mac/scheduler_grid.cc +++ b/srsenb/src/stack/mac/scheduler_grid.cc @@ -89,7 +89,7 @@ const sched_ue::sched_dci_cce_t* pdcch_grid_t::get_cce_loc_table(alloc_type_t al case alloc_type_t::UL_DATA: return user->get_locations(current_cfix + 1, sf_idx); } - return NULL; + return nullptr; } bool pdcch_grid_t::alloc_dci(alloc_type_t alloc_type, uint32_t aggr_idx, sched_ue* user) @@ -98,7 +98,7 @@ bool pdcch_grid_t::alloc_dci(alloc_type_t alloc_type, uint32_t aggr_idx, sched_u /* Get DCI Location Table */ const sched_ue::sched_dci_cce_t* dci_locs = get_cce_loc_table(alloc_type, user); - if (!dci_locs) { + if (dci_locs == nullptr) { return false; } @@ -199,16 +199,17 @@ void pdcch_grid_t::get_allocs(alloc_result_t* vec, pdcch_mask_t* tot_mask, size_ { // if alloc tree is empty if (prev_start == prev_end) { - if (vec) + if (vec != nullptr) { vec->clear(); - if (tot_mask) { + } + if (tot_mask != nullptr) { tot_mask->reset(); } return; } // set vector of allocations - if (vec) { + if (vec != nullptr) { vec->clear(); size_t i = prev_start + idx; while (dci_alloc_tree[i].first >= 0) { @@ -220,7 +221,7 @@ void pdcch_grid_t::get_allocs(alloc_result_t* vec, pdcch_mask_t* tot_mask, size_ } // set final cce mask - if (tot_mask) { + if (tot_mask != nullptr) { *tot_mask = dci_alloc_tree[prev_start + idx].second.total_mask; } } @@ -293,6 +294,7 @@ void tti_grid_t::new_tti(uint32_t tti_rx_, uint32_t start_cfi) pdcch_alloc.new_tti(tti_rx, start_cfi); } +//! Allocates CCEs and RBs for the given mask and allocation type (e.g. data, BC, RAR, paging) alloc_outcome_t tti_grid_t::alloc_dl(uint32_t aggr_lvl, alloc_type_t alloc_type, rbgmask_t alloc_mask, sched_ue* user) { // Check RBG collision @@ -312,6 +314,7 @@ alloc_outcome_t tti_grid_t::alloc_dl(uint32_t aggr_lvl, alloc_type_t alloc_type, return alloc_outcome_t::SUCCESS; } +//! Allocates CCEs and RBs for control allocs. It allocates RBs in a contiguous manner. tti_grid_t::ctrl_alloc_t tti_grid_t::alloc_dl_ctrl(uint32_t aggr_lvl, alloc_type_t alloc_type) { rbg_range_t range; @@ -334,10 +337,11 @@ tti_grid_t::ctrl_alloc_t tti_grid_t::alloc_dl_ctrl(uint32_t aggr_lvl, alloc_type return {alloc_dl(aggr_lvl, alloc_type, new_mask), range}; } +//! Allocates CCEs and RBs for a user DL data alloc. alloc_outcome_t tti_grid_t::alloc_dl_data(sched_ue* user, const rbgmask_t& user_mask) { srslte_dci_format_t dci_format = user->get_dci_format(); - uint32_t aggr_level = user->get_aggr_level(srslte_dci_format_sizeof(&cell_cfg->cell, NULL, NULL, dci_format)); + uint32_t aggr_level = user->get_aggr_level(srslte_dci_format_sizeof(&cell_cfg->cell, nullptr, nullptr, dci_format)); return alloc_dl(aggr_level, alloc_type_t::DL_DATA, user_mask, user); } @@ -355,7 +359,8 @@ alloc_outcome_t tti_grid_t::alloc_ul_data(sched_ue* user, ul_harq_proc::ul_alloc // Generate PDCCH except for RAR and non-adaptive retx if (needs_pdcch) { - uint32_t aggr_idx = user->get_aggr_level(srslte_dci_format_sizeof(&cell_cfg->cell, NULL, NULL, SRSLTE_DCI_FORMAT0)); + uint32_t aggr_idx = + user->get_aggr_level(srslte_dci_format_sizeof(&cell_cfg->cell, nullptr, nullptr, SRSLTE_DCI_FORMAT0)); if (not pdcch_alloc.alloc_dci(alloc_type_t::UL_DATA, aggr_idx, user)) { return alloc_outcome_t::DCI_COLLISION; } diff --git a/srsenb/test/mac/scheduler_test.cc b/srsenb/test/mac/scheduler_test.cc index 536bd44d9..7b1800538 100644 --- a/srsenb/test/mac/scheduler_test.cc +++ b/srsenb/test/mac/scheduler_test.cc @@ -127,15 +127,15 @@ int main(int argc, char *argv[]) srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg; bzero(&bearer_cfg, sizeof(srsenb::sched_interface::ue_bearer_cfg_t)); - bearer_cfg.direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; + bearer_cfg.direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; my_sched.ue_cfg(rnti, &ue_cfg); my_sched.bearer_ue_cfg(rnti, 0, &bearer_cfg); - //my_sched.dl_rlc_buffer_state(rnti, 0, 1e6, 0); - my_sched.ul_bsr(rnti, 0, 1e6); + // my_sched.dl_rlc_buffer_state(rnti, 0, 1e6, 0); + my_sched.ul_bsr(rnti, 0, 1e6, true); - bool running = true; - uint32_t tti = 0; + bool running = true; + uint32_t tti = 0; while(running) { log_out.step(tti); if (tti > 50) { diff --git a/srsenb/test/mac/scheduler_test_rand.cc b/srsenb/test/mac/scheduler_test_rand.cc index 94e9492b3..9123b8f53 100644 --- a/srsenb/test/mac/scheduler_test_rand.cc +++ b/srsenb/test/mac/scheduler_test_rand.cc @@ -226,6 +226,7 @@ struct sched_tester : public srsenb::sched { void assert_no_empty_allocs(); void test_collisions(); void test_harqs(); + void test_sibs(); void run_tti(uint32_t tti_rx); private: @@ -381,6 +382,7 @@ void sched_tester::process_results() test_collisions(); assert_no_empty_allocs(); test_harqs(); + test_sibs(); } void sched_tester::run_tti(uint32_t tti_rx) @@ -712,6 +714,40 @@ void sched_tester::test_harqs() // } } +void sched_tester::test_sibs() +{ + uint32_t sfn = tti_data.tti_tx_dl / 10; + uint32_t sf_idx = TTI_TX(tti_data.tti_rx) % 10; + bool sib1_present = ((sfn % 2) == 0) and sf_idx == 5; + + using bc_elem = sched_interface::dl_sched_bc_t; + bc_elem* bc_begin = &tti_data.sched_result_dl.bc[0]; + bc_elem* bc_end = &tti_data.sched_result_dl.bc[tti_data.sched_result_dl.nof_bc_elems]; + + /* Test if SIB1 was correctly scheduled */ + if (sib1_present) { + auto it = std::find_if(bc_begin, bc_end, [](bc_elem& elem) { return elem.index == 0; }); + CondError(it == bc_end, "Failed to allocate SIB1 in even sfn, sf_idx==5\n"); + } + + /* Test if any SIB was scheduled outside of its window */ + for (bc_elem* bc = bc_begin; bc != bc_end; ++bc) { + if (bc->index == 0) { + continue; + } + uint32_t x = (bc->index - 1) * cfg.si_window_ms; + uint32_t sf = x % 10; + uint32_t sfn_start = sfn; + while ((sfn_start % cfg.sibs[bc->index].period_rf) != x / 10) { + sfn_start--; + } + uint32_t win_start = sfn_start * 10 + sf; + uint32_t win_end = win_start + cfg.si_window_ms; + CondError(tti_data.tti_tx_dl < win_start or tti_data.tti_tx_dl > win_end, + "Scheduled SIB is outside of its SIB window\n"); + } +} + void sched_tester::test_collisions() { tti_sched_t* tti_sched = get_tti_sched(tti_data.tti_rx);