diff --git a/lib/include/srslte/common/bounded_bitset.h b/lib/include/srslte/common/bounded_bitset.h index 939ba6efa..9e3c3fa10 100644 --- a/lib/include/srslte/common/bounded_bitset.h +++ b/lib/include/srslte/common/bounded_bitset.h @@ -64,6 +64,19 @@ public: } } + void set(size_t pos, bool val) noexcept + { + if (pos >= size()) { + srslte::logmap::get("COMM")->error("ERROR: bitset out of bounds: %zd>=%zd\n", pos, size()); + return; + } + if (val) { + set_(pos); + } else { + reset_(pos); + } + } + void set(size_t pos) noexcept { if (pos >= size()) { @@ -76,7 +89,7 @@ public: void reset(size_t pos) noexcept { if (pos >= size()) { - printf("ERROR: bitset out of bounds: %zd>=%zd\n", pos, size()); + srslte::logmap::get("COMM")->error("ERROR: bitset out of bounds: %zd>=%zd\n", pos, size()); return; } reset_(pos); @@ -92,7 +105,7 @@ public: bool test(size_t pos) const noexcept { if (pos >= size()) { - printf("ERROR: bitset out of bounds: %zd>=%zd\n", pos, size()); + srslte::logmap::get("COMM")->error("ERROR: bitset out of bounds: %zd>=%zd\n", pos, size()); return false; } return test_(pos); @@ -110,7 +123,8 @@ public: bounded_bitset& fill(size_t startpos, size_t endpos, bool value = true) noexcept { if (endpos > size() or startpos > endpos) { - printf("ERROR: bounds (%zd, %zd) are not valid for bitset of size: %zd\n", startpos, endpos, size()); + srslte::logmap::get("COMM")->error( + "ERROR: bounds (%zd, %zd) are not valid for bitset of size: %zd\n", startpos, endpos, size()); return *this; } // NOTE: can be optimized @@ -154,7 +168,8 @@ public: bool any(size_t start, size_t stop) const noexcept { if (start > stop or stop > size()) { - printf("ERROR: bounds (%zd, %zd) are not valid for bitset of size: %zd\n", start, stop, size()); + srslte::logmap::get("COMM")->error( + "ERROR: bounds (%zd, %zd) are not valid for bitset of size: %zd\n", start, stop, size()); return false; } // NOTE: can be optimized @@ -174,8 +189,8 @@ public: for (size_t i = 0; i < nof_words_(); i++) { // result += __builtin_popcountl(buffer[i]); word_t w = buffer[i]; - for (; w; w >>= 1) { - result += (w & 1); + for (; w; w >>= 1u) { + result += (w & 1u); } } return result; @@ -187,8 +202,9 @@ public: return false; } for (uint32_t i = 0; i < nof_words_(); ++i) { - if (buffer[i] != other.buffer[i]) + if (buffer[i] != other.buffer[i]) { return false; + } } return true; } @@ -198,7 +214,8 @@ public: bounded_bitset& operator|=(const bounded_bitset& other) noexcept { if (other.size() != size()) { - printf("ERROR: operator|= called for bitsets of different sizes (%zd!=%zd)\n", size(), other.size()); + srslte::logmap::get("COMM")->error( + "ERROR: operator|= called for bitsets of different sizes (%zd!=%zd)\n", size(), other.size()); return *this; } for (size_t i = 0; i < nof_words_(); ++i) { @@ -210,7 +227,8 @@ public: bounded_bitset& operator&=(const bounded_bitset& other) noexcept { if (other.size() != size()) { - printf("ERROR: operator&= called for bitsets of different sizes (%zd!=%zd)\n", size(), other.size()); + srslte::logmap::get("COMM")->error( + "ERROR: operator&= called for bitsets of different sizes (%zd!=%zd)\n", size(), other.size()); return *this; } for (size_t i = 0; i < nof_words_(); ++i) { @@ -249,7 +267,7 @@ public: uint64_t to_uint64() const noexcept { if (nof_words_() > 1) { - printf("ERROR: cannot convert bitset of size %zd bits to uint64_t\n", size()); + srslte::logmap::get("COMM")->error("ERROR: cannot convert bitset of size %zd bits to uint64_t\n", size()); return 0; } return get_word_(0); diff --git a/lib/include/srslte/common/pdu.h b/lib/include/srslte/common/pdu.h index c281a958d..8bdfc8f6c 100644 --- a/lib/include/srslte/common/pdu.h +++ b/lib/include/srslte/common/pdu.h @@ -22,6 +22,7 @@ #ifndef SRSLTE_PDU_H #define SRSLTE_PDU_H +#include "srslte/common/bounded_bitset.h" #include "srslte/common/interfaces_common.h" #include "srslte/common/log.h" #include @@ -270,6 +271,7 @@ public: bool set_bsr(uint32_t buff_size[4], sch_subh::cetype format); bool set_con_res_id(uint64_t con_res_id); bool set_ta_cmd(uint8_t ta_cmd); + bool set_scell_activation_cmd(srslte::bounded_bitset<32> active_cc_idxs); bool set_phr(float phr); void set_padding(); void set_padding(uint32_t padding_len); diff --git a/lib/include/srslte/interfaces/sched_interface.h b/lib/include/srslte/interfaces/sched_interface.h index 75fdf21a8..d34a0275d 100644 --- a/lib/include/srslte/interfaces/sched_interface.h +++ b/lib/include/srslte/interfaces/sched_interface.h @@ -128,9 +128,8 @@ public: struct ue_cfg_t { struct cc_cfg_t { - uint32_t enb_cc_idx = 0; ///< eNB CC index - uint32_t periodic_cqi_i = 0; ///< Periodic CQI configuration for this Scell - bool operator==(const cc_cfg_t& c) { return enb_cc_idx == c.enb_cc_idx; } + bool active = false; + uint32_t enb_cc_idx = 0; ///< eNB CC index }; /* ue capabilities, etc */ uint32_t maxharq_tx = 5; @@ -276,7 +275,8 @@ public: virtual int ul_sched(uint32_t tti, uint32_t cc_idx, ul_sched_res_t& sched_result) = 0; /* Custom */ - virtual void set_dl_tti_mask(uint8_t* tti_mask, uint32_t nof_sfs) = 0; + virtual void set_dl_tti_mask(uint8_t* tti_mask, uint32_t nof_sfs) = 0; + virtual const ue_cfg_t* get_ue_cfg(uint16_t rnti) = 0; }; } // namespace srsenb diff --git a/lib/src/common/pdu.cc b/lib/src/common/pdu.cc index 9951d83ed..4eace9361 100644 --- a/lib/src/common/pdu.cc +++ b/lib/src/common/pdu.cc @@ -628,6 +628,24 @@ bool sch_subh::set_ta_cmd(uint8_t ta_cmd) } } +bool sch_subh::set_scell_activation_cmd(srslte::bounded_bitset<32> active_cc_idxs) +{ + const uint32_t nof_octets = active_cc_idxs.size() <= 8 ? 1 : 4; + if (not((sch_pdu*)parent)->has_space_ce(nof_octets)) { + return false; + } + // first bit is reserved + active_cc_idxs.set(0, false); + uint32_t toencode = (uint32_t)active_cc_idxs.to_uint64(); + for (uint32_t i = 0; i < nof_octets; ++i) { + w_payload_ce[i] = (uint8_t)((toencode >> (8u * i)) & 0xffu); + } + lcid = SCELL_ACTIVATION; + ((sch_pdu*)parent)->update_space_ce(nof_octets); + nof_bytes = nof_octets; + return true; +} + bool sch_subh::set_next_mch_sched_info(uint8_t lcid_, uint16_t mtch_stop) { if (((sch_pdu*)parent)->has_space_ce(2, true)) { diff --git a/srsenb/hdr/stack/mac/mac.h b/srsenb/hdr/stack/mac/mac.h index 678194142..9b359f3e8 100644 --- a/srsenb/hdr/stack/mac/mac.h +++ b/srsenb/hdr/stack/mac/mac.h @@ -80,8 +80,8 @@ public: void reset() override; /* Manages UE scheduling context */ - int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg); - int ue_rem(uint16_t rnti); + int ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) override; + int ue_rem(uint16_t rnti) override; // Indicates that the PHY config dedicated has been enabled or not void phy_config_enabled(uint16_t rnti, bool enabled); diff --git a/srsenb/hdr/stack/mac/scheduler.h b/srsenb/hdr/stack/mac/scheduler.h index d95d9324c..aceb4023c 100644 --- a/srsenb/hdr/stack/mac/scheduler.h +++ b/srsenb/hdr/stack/mac/scheduler.h @@ -162,9 +162,10 @@ public: /* Custom functions */ - void set_dl_tti_mask(uint8_t* tti_mask, uint32_t nof_sfs) final; - void tpc_inc(uint16_t rnti); - void tpc_dec(uint16_t rnti); + void set_dl_tti_mask(uint8_t* tti_mask, uint32_t nof_sfs) final; + void tpc_inc(uint16_t rnti); + void tpc_dec(uint16_t rnti); + const ue_cfg_t* get_ue_cfg(uint16_t rnti) final; // Static Methods static uint32_t get_rvidx(uint32_t retx_idx) diff --git a/srsenb/hdr/stack/mac/scheduler_ue.h b/srsenb/hdr/stack/mac/scheduler_ue.h index e1e346039..4c0a2dfd6 100644 --- a/srsenb/hdr/stack/mac/scheduler_ue.h +++ b/srsenb/hdr/stack/mac/scheduler_ue.h @@ -44,7 +44,10 @@ struct sched_dci_cce_t { struct sched_ue_carrier { const static int SCHED_MAX_HARQ_PROC = SRSLTE_FDD_NOF_HARQ; - sched_ue_carrier(const sched_interface::ue_cfg_t& cfg_, const sched_cell_params_t& cell_cfg_, uint16_t rnti_); + sched_ue_carrier(const sched_interface::ue_cfg_t& cfg_, + const sched_cell_params_t& cell_cfg_, + uint16_t rnti_, + uint32_t ue_cc_idx); void reset(); void set_cfg(const sched_interface::ue_cfg_t& cfg); ///< reconfigure ue carrier @@ -62,6 +65,8 @@ struct sched_ue_carrier { int alloc_tbs_ul(uint32_t nof_prb, uint32_t nof_re, uint32_t req_bytes, int* mcs); uint32_t get_required_prb_ul(uint32_t req_bytes); const sched_cell_params_t* get_cell_cfg() const { return cell_params; } + bool is_active() const { return active; } + uint32_t get_ue_cc_idx() const { return ue_cc_idx; } std::array dl_harq = {}; std::array ul_harq = {}; @@ -83,10 +88,15 @@ struct sched_ue_carrier { std::array, 3> dci_locations = {}; private: + // config srslte::log* log_h = nullptr; const sched_interface::ue_cfg_t* cfg = nullptr; const sched_cell_params_t* cell_params = nullptr; uint16_t rnti; + uint32_t ue_cc_idx = 0; + + // state + bool active = false; }; /** This class is designed to be thread-safe because it is called from workers through scheduler thread and from @@ -131,10 +141,11 @@ public: void tpc_inc(); void tpc_dec(); - dl_harq_proc* find_dl_harq(uint32_t tti_rx, uint32_t cc_idx); - dl_harq_proc* get_dl_harq(uint32_t idx, uint32_t cc_idx); - uint16_t get_rnti() const { return rnti; } - std::pair get_cell_index(uint32_t enb_cc_idx) const; + dl_harq_proc* find_dl_harq(uint32_t tti_rx, uint32_t cc_idx); + dl_harq_proc* get_dl_harq(uint32_t idx, uint32_t cc_idx); + uint16_t get_rnti() const { return rnti; } + std::pair get_cell_index(uint32_t enb_cc_idx) const; + const sched_interface::ue_cfg_t& get_ue_cfg() const { return cfg; } /******************************************************* * Functions used by scheduler metric objects diff --git a/srsenb/src/stack/enb_stack_lte.cc b/srsenb/src/stack/enb_stack_lte.cc index 7b157ac47..354fcd549 100644 --- a/srsenb/src/stack/enb_stack_lte.cc +++ b/srsenb/src/stack/enb_stack_lte.cc @@ -70,6 +70,7 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_) rrc_cfg = rrc_cfg_; // setup logging for each layer + srslte::logmap::get_instance()->set_default_logger(logger); mac_log.init("MAC ", logger, true); rlc_log.init("RLC ", logger); pdcp_log.init("PDCP", logger); diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 4cf409595..85cbda23e 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -195,31 +195,33 @@ void mac::phy_config_enabled(uint16_t rnti, bool enabled) // Update UE configuration int mac::ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t* cfg) { - int ret = -1; srslte::rwlock_read_guard lock(rwlock); - if (ue_db.count(rnti) > 0) { - // Add RNTI to the PHY (pregerate signals) now instead of after PRACH - if (!ue_db[rnti]->is_phy_added) { - ue_db[rnti]->is_phy_added = true; - Info("Registering rnti=0x%x to PHY...\n", rnti); - // Register new user in PHY - if (phy_h->add_rnti(rnti, 0, false)) { - Error("Registering new ue rnti=0x%x to PHY\n", rnti); - } - Info("Done registering rnti=0x%x to PHY...\n", rnti); - } - - // Update Scheduler configuration - if ((cfg != nullptr) ? (scheduler.ue_cfg(rnti, *cfg) != SRSLTE_SUCCESS) : false) { - Error("Registering new UE rnti=0x%x to SCHED\n", rnti); - } else { - ret = 0; - } - } else { + auto it = ue_db.find(rnti); + ue* ue_ptr = nullptr; + if (it == ue_db.end()) { Error("User rnti=0x%x not found\n", rnti); + return SRSLTE_ERROR; } - return ret; + ue_ptr = it->second; + + // Add RNTI to the PHY (pregenerate signals) now instead of after PRACH + if (not ue_ptr->is_phy_added) { + ue_ptr->is_phy_added = true; + Info("Registering rnti=0x%x to PHY...\n", rnti); + // Register new user in PHY + if (phy_h->add_rnti(rnti, 0, false) == SRSLTE_ERROR) { + Error("Registering new ue rnti=0x%x to PHY\n", rnti); + } + Info("Done registering rnti=0x%x to PHY...\n", rnti); + } + + // Update Scheduler configuration + if (cfg != nullptr and scheduler.ue_cfg(rnti, *cfg) == SRSLTE_ERROR) { + Error("Registering new UE rnti=0x%x to SCHED\n", rnti); + return SRSLTE_ERROR; + } + return SRSLTE_SUCCESS; } // Removes UE from DB @@ -446,10 +448,10 @@ int mac::rach_detected(uint32_t tti, uint32_t enb_cc_idx, uint32_t preamble_idx, // Add new user to the scheduler so that it can RX/TX SRB0 sched_interface::ue_cfg_t ue_cfg = {}; ue_cfg.supported_cc_list.emplace_back(); - ue_cfg.supported_cc_list.back().enb_cc_idx = enb_cc_idx; - ue_cfg.supported_cc_list.back().periodic_cqi_i = 0; - ue_cfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; - ue_cfg.dl_cfg.tm = SRSLTE_TM1; + ue_cfg.supported_cc_list.back().active = true; + ue_cfg.supported_cc_list.back().enb_cc_idx = enb_cc_idx; + ue_cfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; + ue_cfg.dl_cfg.tm = SRSLTE_TM1; if (scheduler.ue_cfg(rnti, ue_cfg) != SRSLTE_SUCCESS) { Error("Registering new user rnti=0x%x to SCHED\n", rnti); return -1; diff --git a/srsenb/src/stack/mac/scheduler.cc b/srsenb/src/stack/mac/scheduler.cc index 6a6fa87fb..2fcc9765c 100644 --- a/srsenb/src/stack/mac/scheduler.cc +++ b/srsenb/src/stack/mac/scheduler.cc @@ -366,6 +366,13 @@ void sched::tpc_dec(uint16_t rnti) ue_db_access(rnti, [](sched_ue& ue) { ue.tpc_dec(); }); } +const sched::ue_cfg_t* sched::get_ue_cfg(uint16_t rnti) +{ + const ue_cfg_t* cfg = nullptr; + ue_db_access(rnti, [&cfg](sched_ue& ue) { cfg = &ue.get_ue_cfg(); }); + return cfg; +} + /******************************************************* * * Main sched functions diff --git a/srsenb/src/stack/mac/scheduler_ue.cc b/srsenb/src/stack/mac/scheduler_ue.cc index cd978f959..759499778 100644 --- a/srsenb/src/stack/mac/scheduler_ue.cc +++ b/srsenb/src/stack/mac/scheduler_ue.cc @@ -55,6 +55,11 @@ uint32_t get_tbs_bytes(uint32_t mcs, uint32_t nof_alloc_prb, bool is_ul) } // namespace sched_utils +bool operator==(const sched_interface::ue_cfg_t::cc_cfg_t& lhs, const sched_interface::ue_cfg_t::cc_cfg_t& rhs) +{ + return lhs.enb_cc_idx == rhs.enb_cc_idx and lhs.active == rhs.active; +} + /******************************************************* * * Initialization and configuration functions @@ -94,10 +99,6 @@ void sched_ue::set_cfg(const sched_interface::ue_cfg_t& cfg_) cell = main_cc_params->cfg.cell; max_msg3retx = main_cc_params->cfg.maxharq_msg3tx; } - bool maxharq_tx_changed = cfg.maxharq_tx != cfg_.maxharq_tx; - bool cc_changed = - cfg.supported_cc_list.size() != cfg_.supported_cc_list.size() or - not std::equal(cfg.supported_cc_list.begin(), cfg.supported_cc_list.end(), cfg_.supported_cc_list.begin()); // update configuration cfg = cfg_; @@ -108,21 +109,23 @@ void sched_ue::set_cfg(const sched_interface::ue_cfg_t& cfg_) } // either add a new carrier, or reconfigure existing one + bool scell_activation_state_changed = false; for (auto& cc_cfg : cfg.supported_cc_list) { sched_ue_carrier* c = get_ue_carrier(cc_cfg.enb_cc_idx); if (c == nullptr) { // add new carrier to sched_ue - carriers.emplace_back(cfg, (*cell_params_list)[cc_cfg.enb_cc_idx], rnti); + carriers.emplace_back(cfg, (*cell_params_list)[cc_cfg.enb_cc_idx], rnti, carriers.size()); + scell_activation_state_changed |= carriers.size() > 1 and carriers.back().is_active(); } else { - // reconfiguration of carrier might be needed - if (maxharq_tx_changed) { - c->set_cfg(cfg); - } + // if SCell state changed + scell_activation_state_changed = c->is_active() != cc_cfg.active and c->get_ue_cc_idx() != 0; + // reconfiguration of carrier might be needed. + c->set_cfg(cfg); } } - - if (cc_changed) { - pending_ces.push_back(ce_cmd{srslte::sch_subh::SCELL_ACTIVATION}); + if (scell_activation_state_changed) { + pending_ces.emplace_back(srslte::sch_subh::SCELL_ACTIVATION); + log_h->info("SCHED: Scheduling SCell Activation CMD for rnti=0x%x\n", rnti); } } } @@ -1058,10 +1061,12 @@ int sched_ue::cqi_to_tbs(uint32_t cqi, sched_ue_carrier::sched_ue_carrier(const sched_interface::ue_cfg_t& cfg_, const sched_cell_params_t& cell_cfg_, - uint16_t rnti_) : + uint16_t rnti_, + uint32_t ue_cc_idx_) : cell_params(&cell_cfg_), rnti(rnti_), - log_h(srslte::logmap::get("MAC ")) + log_h(srslte::logmap::get("MAC ")), + ue_cc_idx(ue_cc_idx_) { // Init HARQ processes for (uint32_t i = 0; i < dl_harq.size(); ++i) { @@ -1108,12 +1113,17 @@ void sched_ue_carrier::reset() void sched_ue_carrier::set_cfg(const sched_interface::ue_cfg_t& cfg_) { + if (cfg != nullptr and cfg->maxharq_tx == cfg_.maxharq_tx and active == cfg->supported_cc_list[ue_cc_idx].active) { + // nothing changed + return; + } cfg = &cfg_; // Config HARQ processes for (uint32_t i = 0; i < dl_harq.size(); ++i) { dl_harq[i].set_cfg(cfg->maxharq_tx); ul_harq[i].set_cfg(cfg->maxharq_tx); } + active = cfg->supported_cc_list[ue_cc_idx].active; } void sched_ue_carrier::reset_old_pending_pids(uint32_t tti_rx) diff --git a/srsenb/src/stack/mac/ue.cc b/srsenb/src/stack/mac/ue.cc index 3fd7c1b2e..f26c5d112 100644 --- a/srsenb/src/stack/mac/ue.cc +++ b/srsenb/src/stack/mac/ue.cc @@ -24,6 +24,7 @@ #include #include "srsenb/hdr/stack/mac/ue.h" +#include "srslte/common/bounded_bitset.h" #include "srslte/interfaces/enb_interfaces.h" #define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) @@ -424,6 +425,21 @@ void ue::allocate_ce(srslte::sch_pdu* pdu, uint32_t lcid) Error("CE: Setting Contention Resolution ID CE. No space for a subheader\n"); } break; + case srslte::sch_subh::SCELL_ACTIVATION: + if (pdu->new_subh()) { + const sched_interface::ue_cfg_t* sched_cfg = sched->get_ue_cfg(rnti); + srslte::bounded_bitset<32> active_cc_list(sched_cfg->supported_cc_list.size()); + for (uint32_t i = 0; i < sched_cfg->supported_cc_list.size(); ++i) { + active_cc_list.set(i, sched_cfg->supported_cc_list[i].active); + } + if (pdu->get()->set_scell_activation_cmd(active_cc_list)) { + Info("CE: Added SCell Activation CE.\n"); + } else { + Error("CE: Setting SCell Activation CE\n"); + } + } else { + Error("CE: Setting SCell Activation CE. No space for a subheader\n"); + } default: Error("CE: Allocating CE=0x%x. Not supported\n", lcid); break; diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index 4b7695743..657c21025 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -1251,8 +1251,8 @@ void rrc::ue::handle_rrc_reconf_complete(rrc_conn_recfg_complete_s* msg, srslte: auto it = std::find_if(list.begin(), list.end(), [i](const cc_cfg_t& u) { return u.enb_cc_idx == i; }); if (it == list.end()) { list.emplace_back(); - list.back().enb_cc_idx = i; - list.back().periodic_cqi_i = 0; + list.back().active = true; + list.back().enb_cc_idx = i; } } parent->mac->ue_cfg(rnti, ¤t_sched_ue_cfg);