diff --git a/srsenb/hdr/stack/rrc/rrc_cell_cfg.h b/srsenb/hdr/stack/rrc/rrc_cell_cfg.h index c9edbfc11..6fc841434 100644 --- a/srsenb/hdr/stack/rrc/rrc_cell_cfg.h +++ b/srsenb/hdr/stack/rrc/rrc_cell_cfg.h @@ -113,6 +113,7 @@ struct cell_ctxt_dedicated { cell_ctxt_dedicated& operator=(cell_ctxt_dedicated&&) noexcept = default; uint32_t get_dl_earfcn() const { return cell_common->cell_cfg.dl_earfcn; } + uint32_t get_pci() const { return cell_common->cell_cfg.pci; } }; /** Class used to handle the allocation of a UE's resources across its cells */ @@ -136,13 +137,17 @@ public: { return (ue_cc_idx < nof_cells()) ? &cell_ded_list[ue_cc_idx] : nullptr; } - cell_ctxt_dedicated* get_enb_cc_idx(uint32_t enb_cc_idx); - size_t nof_cells() const { return cell_ded_list.size(); } - bool is_allocated() const { return nof_cells() > 0; } + cell_ctxt_dedicated* get_enb_cc_idx(uint32_t enb_cc_idx); + const cell_ctxt_dedicated* find_cell(uint32_t earfcn, uint32_t pci) const; + size_t nof_cells() const { return cell_ded_list.size(); } + bool is_allocated() const { return nof_cells() > 0; } - using iterator = std::vector::iterator; - iterator begin() { return cell_ded_list.begin(); } - iterator end() { return cell_ded_list.end(); } + using iterator = std::vector::iterator; + using const_iterator = std::vector::const_iterator; + iterator begin() { return cell_ded_list.begin(); } + iterator end() { return cell_ded_list.end(); } + const_iterator begin() const { return cell_ded_list.begin(); } + const_iterator end() const { return cell_ded_list.end(); } struct sr_res_t { int sr_sched_sf_idx = 0; diff --git a/srsenb/hdr/stack/rrc/rrc_config.h b/srsenb/hdr/stack/rrc/rrc_config.h index 247ff2811..924d70b96 100644 --- a/srsenb/hdr/stack/rrc/rrc_config.h +++ b/srsenb/hdr/stack/rrc/rrc_config.h @@ -74,7 +74,7 @@ constexpr uint32_t UE_PCELL_CC_IDX = 0; struct ue_var_cfg_t { asn1::rrc::rr_cfg_ded_s rr_cfg; - asn1::rrc::meas_gap_cfg_c meas_gaps; + asn1::rrc::meas_cfg_s meas_cfg; asn1::rrc::scell_to_add_mod_list_r10_l scells; }; diff --git a/srsenb/hdr/stack/rrc/rrc_mobility.h b/srsenb/hdr/stack/rrc/rrc_mobility.h index 17355490e..415173c0b 100644 --- a/srsenb/hdr/stack/rrc/rrc_mobility.h +++ b/srsenb/hdr/stack/rrc/rrc_mobility.h @@ -115,7 +115,8 @@ private: // Handover to target cell void fill_mobility_reconf_common(asn1::rrc::dl_dcch_msg_s& msg, const cell_info_common& target_cell, - uint32_t src_dl_earfcn); + uint32_t src_dl_earfcn, + uint32_t src_pci); bool apply_ho_prep_cfg(const asn1::rrc::ho_prep_info_r8_ies_s& ho_prep, const asn1::s1ap::ho_request_s& ho_req_msg); rrc::ue* rrc_ue = nullptr; @@ -124,7 +125,7 @@ private: srslte::log_ref rrc_log; // vars - var_meas_cfg_t ue_var_meas; + asn1::rrc::meas_cfg_s current_meas_cfg; asn1::rrc::rrc_conn_recfg_complete_s pending_recfg_complete; // events diff --git a/srsenb/hdr/stack/rrc/ue_meas_cfg.h b/srsenb/hdr/stack/rrc/ue_meas_cfg.h new file mode 100644 index 000000000..030c61c94 --- /dev/null +++ b/srsenb/hdr/stack/rrc/ue_meas_cfg.h @@ -0,0 +1,78 @@ +/* + * Copyright 2013-2020 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_UE_MEAS_CFG_H +#define SRSLTE_UE_MEAS_CFG_H + +#include "srslte/asn1/rrc/meascfg.h" + +namespace srsenb { + +// fwd declarations +struct rrc_cfg_t; +struct meas_cell_cfg_t; +class cell_ctxt_dedicated_list; + +using meas_obj_t = asn1::rrc::meas_obj_to_add_mod_s; +using meas_obj_list = asn1::rrc::meas_obj_to_add_mod_list_l; +using meas_cell_t = asn1::rrc::cells_to_add_mod_s; +using report_cfg_t = asn1::rrc::report_cfg_to_add_mod_s; +using report_cfg_list = asn1::rrc::report_cfg_to_add_mod_list_l; +using meas_id_t = asn1::rrc::meas_id_to_add_mod_s; +using meas_id_list = asn1::rrc::meas_id_to_add_mod_list_l; + +int get_earfcn(const meas_obj_t& obj); +bool is_same_earfcn(const meas_obj_t& lhs, const meas_obj_t& rhs); + +/// Find MeasObj with same earfcn. Assumes ordered list +meas_obj_t* find_meas_obj(meas_obj_list& l, uint32_t earfcn); +const meas_obj_t* find_meas_obj(const meas_obj_list& l, uint32_t earfcn); + +/// Add EARFCN to the MeasObjToAddModList +std::pair add_meas_obj(meas_obj_list& list, uint32_t dl_earfcn); + +std::tuple add_cell_enb_cfg(meas_obj_list& meas_obj_list, + const meas_cell_cfg_t& cellcfg); + +report_cfg_t* add_report_cfg(report_cfg_list& list, const asn1::rrc::report_cfg_eutra_s& reportcfg); + +meas_id_t* add_measid_cfg(meas_id_list& meas_id_list, uint8_t measobjid, uint8_t measrepid); + +/** + * Finds a cell in meas_obj_list based on pci and earfcn + * @return pair of (meas_obj,cell_obj). If no cell has frequency==earfcn, meas_obj=nullptr + */ +std::pair find_cell(meas_obj_list& l, uint32_t earfcn, uint32_t pci); + +bool compute_diff_meascfg(const asn1::rrc::meas_cfg_s& current_meascfg, + const asn1::rrc::meas_cfg_s& target_meascfg, + asn1::rrc::meas_cfg_s& diff_meascfg); + +bool fill_meascfg_enb_cfg(asn1::rrc::meas_cfg_s& meascfg, const cell_ctxt_dedicated_list& ue_cell_list); + +bool apply_meascfg_updates(asn1::rrc::meas_cfg_s& meascfg, + asn1::rrc::meas_cfg_s& current_meascfg, + const cell_ctxt_dedicated_list& ue_cell_list, + int prev_pci = -1); + +} // namespace srsenb + +#endif // SRSLTE_UE_MEAS_CFG_H diff --git a/srsenb/src/stack/rrc/CMakeLists.txt b/srsenb/src/stack/rrc/CMakeLists.txt index 6787e7ff7..2202d9239 100644 --- a/srsenb/src/stack/rrc/CMakeLists.txt +++ b/srsenb/src/stack/rrc/CMakeLists.txt @@ -18,7 +18,7 @@ # and at http://www.gnu.org/licenses/. # -set(SOURCES rrc.cc rrc_ue.cc rrc_mobility.cc rrc_cell_cfg.cc rrc_bearer_cfg.cc mac_controller.cc ue_rr_cfg.cc) +set(SOURCES rrc.cc rrc_ue.cc rrc_mobility.cc rrc_cell_cfg.cc rrc_bearer_cfg.cc mac_controller.cc ue_rr_cfg.cc ue_meas_cfg.cc) add_library(srsenb_rrc STATIC ${SOURCES}) if (ENABLE_5GNR) diff --git a/srsenb/src/stack/rrc/rrc_cell_cfg.cc b/srsenb/src/stack/rrc/rrc_cell_cfg.cc index 5579bb86a..ef29e6ee2 100644 --- a/srsenb/src/stack/rrc/rrc_cell_cfg.cc +++ b/srsenb/src/stack/rrc/rrc_cell_cfg.cc @@ -167,6 +167,14 @@ cell_ctxt_dedicated* cell_ctxt_dedicated_list::get_enb_cc_idx(uint32_t enb_cc_id return it == cell_ded_list.end() ? nullptr : &(*it); } +const cell_ctxt_dedicated* cell_ctxt_dedicated_list::find_cell(uint32_t earfcn, uint32_t pci) const +{ + auto it = std::find_if(cell_ded_list.begin(), cell_ded_list.end(), [earfcn, pci](const cell_ctxt_dedicated& c) { + return c.get_pci() == pci and c.get_dl_earfcn() == earfcn; + }); + return it == cell_ded_list.end() ? nullptr : &(*it); +} + cell_ctxt_dedicated* cell_ctxt_dedicated_list::add_cell(uint32_t enb_cc_idx) { const cell_info_common* cell_common = common_list.get_cc_idx(enb_cc_idx); diff --git a/srsenb/src/stack/rrc/rrc_mobility.cc b/srsenb/src/stack/rrc/rrc_mobility.cc index 20f40d321..ed7757260 100644 --- a/srsenb/src/stack/rrc/rrc_mobility.cc +++ b/srsenb/src/stack/rrc/rrc_mobility.cc @@ -22,6 +22,7 @@ #include "srsenb/hdr/stack/rrc/rrc_mobility.h" #include "srsenb/hdr/stack/rrc/mac_controller.h" #include "srsenb/hdr/stack/rrc/rrc_cell_cfg.h" +#include "srsenb/hdr/stack/rrc/ue_meas_cfg.h" #include "srsenb/hdr/stack/rrc/ue_rr_cfg.h" #include "srslte/asn1/rrc_utils.h" #include "srslte/common/bcd_helpers.h" @@ -581,9 +582,8 @@ bool rrc::ue::rrc_mobility::fill_conn_recfg_no_ho_cmd(asn1::rrc::rrc_conn_recfg_ } // Check if there has been any update in ue_var_meas based on UE current cell list - cell_ctxt_dedicated* pcell = rrc_ue->cell_ded_list.get_ue_cc_idx(UE_PCELL_CC_IDX); - uint32_t src_earfcn = pcell->get_dl_earfcn(); - conn_recfg->meas_cfg_present = update_ue_var_meas_cfg(src_earfcn, *pcell->cell_common, &conn_recfg->meas_cfg); + conn_recfg->meas_cfg_present = apply_meascfg_updates( + conn_recfg->meas_cfg, rrc_ue->current_ue_cfg.meas_cfg, rrc_ue->cell_ded_list); return conn_recfg->meas_cfg_present; } @@ -605,8 +605,10 @@ void rrc::ue::rrc_mobility::handle_ue_meas_report(const meas_report_s& msg) Error("MeasReports regarding non-EUTRA are not supported!\n"); return; } - auto measid_it = srslte::find_rrc_obj_id(ue_var_meas.meas_ids(), meas_res.meas_id); - if (measid_it == ue_var_meas.meas_ids().end()) { + const meas_id_list& measid_list = rrc_ue->current_ue_cfg.meas_cfg.meas_id_to_add_mod_list; + const meas_obj_list& measobj_list = rrc_ue->current_ue_cfg.meas_cfg.meas_obj_to_add_mod_list; + auto measid_it = srslte::find_rrc_obj_id(measid_list, meas_res.meas_id); + if (measid_it == measid_list.end()) { Warning("The measurement ID %d provided by the UE does not exist.\n", meas_res.meas_id); return; } @@ -614,7 +616,7 @@ void rrc::ue::rrc_mobility::handle_ue_meas_report(const meas_report_s& msg) // Find respective ReportCfg and MeasObj ho_meas_report_ev meas_ev{}; - auto obj_it = srslte::find_rrc_obj_id(ue_var_meas.meas_objs(), measid_it->meas_obj_id); + auto obj_it = srslte::find_rrc_obj_id(measobj_list, measid_it->meas_obj_id); meas_ev.meas_obj = &(*obj_it); // iterate from strongest to weakest cell @@ -713,12 +715,7 @@ bool rrc::ue::rrc_mobility::start_ho_preparation(uint32_t target_eci, hoprep_r8.as_cfg_present = true; hoprep_r8.as_cfg.source_rr_cfg = rrc_ue->current_ue_cfg.rr_cfg; hoprep_r8.as_cfg.source_scell_cfg_list_r10.reset(new scell_to_add_mod_list_r10_l{rrc_ue->current_ue_cfg.scells}); - // NOTE: set source_meas_cnfg equal to the UE's current var_meas_cfg - var_meas_cfg_t empty_meascfg{}, &target_var_meas = ue_var_meas; - // // however, reset the MeasObjToAdd Cells, so that the UE does not measure again the target eNB - // meas_obj_to_add_mod_s* obj = rrc_details::binary_find(target_var_meas.meas_objs(), measobj_id); - // obj->meas_obj.meas_obj_eutra().cells_to_add_mod_list.resize(0); - empty_meascfg.compute_diff_meas_cfg(target_var_meas, &hoprep_r8.as_cfg.source_meas_cfg); + hoprep_r8.as_cfg.source_meas_cfg = rrc_ue->current_ue_cfg.meas_cfg; // Get security cfg hoprep_r8.as_cfg.source_security_algorithm_cfg = rrc_ue->ue_security_cfg.get_security_algorithm_cfg(); hoprep_r8.as_cfg.source_ue_id.from_number(rrc_ue->rnti); @@ -801,49 +798,6 @@ bool rrc::ue::rrc_mobility::start_s1_tenb_ho( return is_in_state(); } -bool rrc::ue::rrc_mobility::update_ue_var_meas_cfg(uint32_t src_earfcn, - const cell_info_common& target_pcell, - asn1::rrc::meas_cfg_s* diff_meas_cfg) -{ - // Make UE Target VarMeasCfg based on active cells and parsed Config files - var_meas_cfg_t target_var_meas = var_meas_cfg_t::make(rrc_enb->cfg, target_pcell); - uint32_t target_earfcn = target_pcell.cell_cfg.dl_earfcn; - - // Apply TS 36.331 5.5.6.1 - If Source and Target eNB EARFCNs do no match, update SourceVarMeasCfg.MeasIdList - if (target_earfcn != src_earfcn) { - auto& meas_objs = ue_var_meas.meas_objs(); - meas_obj_to_add_mod_s* found_target_obj = rrc_details::find_meas_obj(meas_objs, target_earfcn); - meas_obj_to_add_mod_s* found_src_obj = rrc_details::find_meas_obj(meas_objs, src_earfcn); - if (found_target_obj != nullptr and found_src_obj != nullptr) { - for (auto& mid : ue_var_meas.meas_ids()) { - if (found_target_obj->meas_obj_id == mid.meas_obj_id) { - mid.meas_obj_id = found_src_obj->meas_obj_id; - } else if (found_src_obj->meas_obj_id == mid.meas_obj_id) { - mid.meas_obj_id = found_target_obj->meas_obj_id; - } - } - } else if (found_src_obj != nullptr) { - for (auto it = ue_var_meas.meas_ids().begin(); it != ue_var_meas.meas_ids().end();) { - if (it->meas_obj_id == found_src_obj->meas_obj_id) { - auto rit = it++; - ue_var_meas.meas_ids().erase(rit); - } else { - ++it; - } - } - } - } - - // Calculate difference between source and target VarMeasCfg - bool meas_cfg_present = ue_var_meas.compute_diff_meas_cfg(target_var_meas, diff_meas_cfg); - - // Update user varMeasCfg to target - ue_var_meas = target_var_meas; - rrc_log->debug_long("New rnti=0x%x varMeasConfig: %s", rrc_ue->rnti, ue_var_meas.to_string().c_str()); - - return meas_cfg_present; -} - /** * @brief Fills RRCConnectionReconfigurationMessage with Handover Command fields that are common to * all types of handover (e.g. S1, intra-enb, X2), namely: @@ -858,7 +812,8 @@ bool rrc::ue::rrc_mobility::update_ue_var_meas_cfg(uint32_t src_e */ void rrc::ue::rrc_mobility::fill_mobility_reconf_common(asn1::rrc::dl_dcch_msg_s& msg, const cell_info_common& target_cell, - uint32_t src_dl_earfcn) + uint32_t src_dl_earfcn, + uint32_t src_pci) { auto& recfg = msg.msg.set_c1().set_rrc_conn_recfg(); recfg.rrc_transaction_id = rrc_ue->transaction_id; @@ -891,7 +846,8 @@ void rrc::ue::rrc_mobility::fill_mobility_reconf_common(asn1::rrc::dl_dcch_msg_s intralte.next_hop_chaining_count = rrc_ue->ue_security_cfg.get_ncc(); // Add MeasConfig of target cell - recfg_r8.meas_cfg_present = update_ue_var_meas_cfg(src_dl_earfcn, target_cell, &recfg_r8.meas_cfg); + recfg_r8.meas_cfg_present = + apply_meascfg_updates(recfg_r8.meas_cfg, rrc_ue->current_ue_cfg.meas_cfg, rrc_ue->cell_ded_list, src_pci); apply_reconf_updates(recfg_r8, rrc_ue->current_ue_cfg, @@ -1062,7 +1018,10 @@ void rrc::ue::rrc_mobility::handle_ho_req(idle_st& s, const ho_req_rx_ev& ho_req const cell_ctxt_dedicated* target_cell = rrc_ue->cell_ded_list.get_ue_cc_idx(UE_PCELL_CC_IDX); // Fill fields common to all types of handover (e.g. new CQI/SR configuration, mobControlInfo) - fill_mobility_reconf_common(dl_dcch_msg, *target_cell->cell_common, hoprep_r8.as_cfg.source_dl_carrier_freq); + fill_mobility_reconf_common(dl_dcch_msg, + *target_cell->cell_common, + hoprep_r8.as_cfg.source_dl_carrier_freq, + hoprep_r8.as_context.reest_info.source_pci); rrc_conn_recfg_r8_ies_s& recfg_r8 = dl_dcch_msg.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8(); // Apply new Security Config based on HandoverRequest @@ -1182,13 +1141,12 @@ bool rrc::ue::rrc_mobility::apply_ho_prep_cfg(const ho_prep_info_r8_ies_s& ho // Save source eNB UE RR cfg as a starting point apply_rr_cfg_ded_diff(rrc_ue->current_ue_cfg.rr_cfg, ho_prep.as_cfg.source_rr_cfg); + // Save measConfig + rrc_ue->current_ue_cfg.meas_cfg = ho_prep.as_cfg.source_meas_cfg; + // Save source UE MAC configuration as a base rrc_ue->mac_ctrl->handle_ho_prep(ho_prep); - // Save measConfig - ue_var_meas = var_meas_cfg_t::make(ho_prep.as_cfg.source_meas_cfg); - rrc_log->debug_long("New rnti=0x%x varMeasConfig: %s", rrc_ue->rnti, ue_var_meas.to_string().c_str()); - return true; } @@ -1281,7 +1239,7 @@ void rrc::ue::rrc_mobility::intraenb_ho_st::enter(rrc_mobility* f, const ho_meas /* Prepare RRC Reconf Message with mobility info */ dl_dcch_msg_s dl_dcch_msg; - f->fill_mobility_reconf_common(dl_dcch_msg, *target_cell, source_cell->cell_cfg.dl_earfcn); + f->fill_mobility_reconf_common(dl_dcch_msg, *target_cell, source_cell->cell_cfg.dl_earfcn, source_cell->cell_cfg.pci); rrc_conn_recfg_r8_ies_s& reconf_r8 = dl_dcch_msg.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8(); // Apply changes to the MAC scheduler diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 21e964583..5d283ecee 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -476,11 +476,6 @@ void rrc::ue::send_connection_reconf(srslte::unique_byte_buffer_t pdu, bool phy_ rrc_conn_recfg.rrc_transaction_id = (uint8_t)((transaction_id++) % 4); rrc_conn_recfg_r8_ies_s& recfg_r8 = rrc_conn_recfg.crit_exts.set_c1().set_rrc_conn_recfg_r8(); - // Add measConfig - if (mobility_handler != nullptr) { - mobility_handler->fill_conn_recfg_no_ho_cmd(&recfg_r8); - } - // Fill RR Config Ded and SCells apply_reconf_updates(recfg_r8, current_ue_cfg, @@ -490,6 +485,11 @@ void rrc::ue::send_connection_reconf(srslte::unique_byte_buffer_t pdu, bool phy_ ue_capabilities, phy_cfg_updated); + // Add measConfig + if (mobility_handler != nullptr) { + mobility_handler->fill_conn_recfg_no_ho_cmd(&recfg_r8); + } + // if no updates were detected, skip rrc reconfiguration if (not(recfg_r8.rr_cfg_ded_present or recfg_r8.meas_cfg_present or recfg_r8.mob_ctrl_info_present or recfg_r8.ded_info_nas_list_present or recfg_r8.security_cfg_ho_present or recfg_r8.non_crit_ext_present)) { diff --git a/srsenb/src/stack/rrc/ue_meas_cfg.cc b/srsenb/src/stack/rrc/ue_meas_cfg.cc new file mode 100644 index 000000000..0fdb0cbce --- /dev/null +++ b/srsenb/src/stack/rrc/ue_meas_cfg.cc @@ -0,0 +1,436 @@ +/* + * Copyright 2013-2020 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/rrc/ue_meas_cfg.h" +#include "srsenb/hdr/stack/rrc/rrc_cell_cfg.h" +#include "srslte/rrc/rrc_cfg_utils.h" + +using namespace asn1::rrc; + +namespace srsenb { + +/*********************************** + * measObjToAddMod + **********************************/ + +int get_earfcn(const meas_obj_t& obj) +{ + if (obj.meas_obj.type().value != meas_obj_t::meas_obj_c_::types_opts::meas_obj_eutra) { + return -1; + } + return obj.meas_obj.meas_obj_eutra().carrier_freq; +} + +bool is_same_earfcn(const meas_obj_t& lhs, const meas_obj_t& rhs) +{ + int freq1 = get_earfcn(lhs); + int freq2 = get_earfcn(rhs); + return freq1 != -1 and freq1 == freq2; +} + +meas_obj_t* find_meas_obj(meas_obj_to_add_mod_list_l& l, uint32_t earfcn) +{ + auto same_earfcn = [earfcn](const meas_obj_t& obj) { return (int)earfcn == get_earfcn(obj); }; + auto it = std::find_if(l.begin(), l.end(), same_earfcn); + return it == l.end() ? nullptr : &(*it); +} +const meas_obj_t* find_meas_obj(const meas_obj_to_add_mod_list_l& l, uint32_t earfcn) +{ + auto same_earfcn = [earfcn](const meas_obj_t& obj) { return (int)earfcn == get_earfcn(obj); }; + auto it = std::find_if(l.begin(), l.end(), same_earfcn); + return it == l.end() ? nullptr : &(*it); +} + +std::pair find_cell(meas_obj_to_add_mod_list_l& l, uint32_t earfcn, uint32_t pci) +{ + // find meas_obj with same earfcn + meas_obj_t* obj = find_meas_obj(l, earfcn); + if (obj == nullptr) { + return std::make_pair(obj, (cells_to_add_mod_s*)nullptr); + } + // find cell with same id + auto& cells = obj->meas_obj.meas_obj_eutra().cells_to_add_mod_list; + auto cell_it = std::find_if(cells.begin(), cells.end(), [pci](const cells_to_add_mod_s& c) { return c.pci == pci; }); + if (cell_it == cells.end()) { + cell_it = nullptr; + } + return std::make_pair(obj, cell_it); +} + +/// Add EARFCN to the MeasObjToAddModList +std::pair add_meas_obj(meas_obj_list& list, uint32_t dl_earfcn) +{ + meas_obj_t* obj = find_meas_obj(list, dl_earfcn); + if (obj != nullptr) { + return {false, obj}; + } + + meas_obj_t new_obj; + new_obj.meas_obj_id = srslte::find_rrc_obj_id_gap(list); + asn1::rrc::meas_obj_eutra_s& eutra = new_obj.meas_obj.set_meas_obj_eutra(); + eutra.carrier_freq = dl_earfcn; + eutra.allowed_meas_bw.value = asn1::rrc::allowed_meas_bw_e::mbw6; // TODO: What value to add here? + eutra.neigh_cell_cfg.from_number(1); // No MBSFN subframes present in neighbors + eutra.offset_freq_present = false; // no offset + obj = srslte::add_rrc_obj(list, new_obj); + return {true, obj}; +} + +/// Add cell parsed in configuration file to the varMeasCfg +std::tuple add_cell_enb_cfg(meas_obj_list& meas_obj_list, + const meas_cell_cfg_t& cellcfg) +{ + bool inserted_flag = true; + + cells_to_add_mod_s new_cell; + asn1::number_to_enum(new_cell.cell_individual_offset, (uint8_t)cellcfg.q_offset); + new_cell.pci = cellcfg.pci; + + std::pair ret = find_cell(meas_obj_list, cellcfg.earfcn, cellcfg.pci); + + if (ret.first != nullptr) { + // there are cells with the same earfcn at least. + if (ret.second != nullptr) { + // the cell already existed. + if (ret.second->cell_individual_offset != new_cell.cell_individual_offset) { + // members of cell were updated + new_cell.cell_idx = ret.second->cell_idx; + *ret.second = new_cell; + } else { + inserted_flag = false; + } + } else { + auto& eutra_obj = ret.first->meas_obj.meas_obj_eutra(); + // pci not found. create new cell + new_cell.cell_idx = srslte::find_rrc_obj_id_gap(eutra_obj.cells_to_add_mod_list); + ret.second = srslte::add_rrc_obj(eutra_obj.cells_to_add_mod_list, new_cell); + eutra_obj.cells_to_add_mod_list_present = true; + } + } else { + // no measobj has been found with same earfcn, create a new one + auto ret2 = add_meas_obj(meas_obj_list, cellcfg.earfcn); + ret.first = ret2.second; + + new_cell.cell_idx = 1; + auto& eutra = ret2.second->meas_obj.meas_obj_eutra(); + eutra.cells_to_add_mod_list_present = true; + eutra.cells_to_add_mod_list.push_back(new_cell); + ret.second = &ret.first->meas_obj.meas_obj_eutra().cells_to_add_mod_list.back(); + } + + return std::make_tuple(inserted_flag, ret.first, ret.second); +} + +/** + * TS 36.331 - Section 5.5.2.5 + * Description: Adds MeasObjtoAddMod to MeasCfg object + */ +meas_obj_to_add_mod_s* meascfg_add_meas_obj(meas_cfg_s* meas_cfg, const meas_obj_to_add_mod_s& meas_obj) +{ + meas_cfg->meas_obj_to_add_mod_list_present = true; + + // search for meas_obj by obj_id to ensure uniqueness (assume sorted) + auto meas_obj_it = srslte::add_rrc_obj_id(meas_cfg->meas_obj_to_add_mod_list, meas_obj.meas_obj_id); + // TODO: Assert dl_earfcn is the same + + auto& target_eutra = meas_obj_it->meas_obj.set_meas_obj_eutra(); + auto& src_eutra = meas_obj.meas_obj.meas_obj_eutra(); + target_eutra.carrier_freq = src_eutra.carrier_freq; + target_eutra.offset_freq_present = src_eutra.offset_freq_present; + target_eutra.offset_freq = src_eutra.offset_freq; + target_eutra.allowed_meas_bw = src_eutra.allowed_meas_bw; + target_eutra.presence_ant_port1 = src_eutra.presence_ant_port1; + target_eutra.neigh_cell_cfg = src_eutra.neigh_cell_cfg; + // do not add cellsToAddModList, blackCells, whiteCells, etc. according to (5.5.2.5 1|1|1) + + return meas_obj_it; +} + +/// adds all the cells that got updated to MeasCfg. +void compute_diff_cells(const meas_obj_eutra_s& src_it, + const meas_obj_eutra_s& target_it, + meas_obj_to_add_mod_s* added_obj) +{ + meas_obj_eutra_s* eutra_obj = &added_obj->meas_obj.meas_obj_eutra(); + srslte::compute_cfg_diff(src_it.cells_to_add_mod_list, + target_it.cells_to_add_mod_list, + eutra_obj->cells_to_add_mod_list, + eutra_obj->cells_to_rem_list); + eutra_obj->cells_to_add_mod_list_present = eutra_obj->cells_to_add_mod_list.size() > 0; + eutra_obj->cells_to_rem_list_present = eutra_obj->cells_to_rem_list.size() > 0; +} + +/** + * Section 5.5.2.4/5, Measurement Object removal and addition/modification + * Description: compute diff between target_cfg and var_meas -> depending on diff, add/remove/update meas_obj in + * meas_cfg + */ +void compute_diff_meas_objs(const meas_cfg_s& prev_cfg, const meas_cfg_s& target_cfg, meas_cfg_s& meas_cfg) +{ + auto rem_func = [&meas_cfg](const meas_obj_t* it) { meas_cfg.meas_obj_to_rem_list.push_back(it->meas_obj_id); }; + auto add_func = [&meas_cfg](const meas_obj_t* it) { meas_cfg.meas_obj_to_add_mod_list.push_back(*it); }; + auto mod_func = [&meas_cfg](const meas_obj_t* src_it, const meas_obj_t* target_it) { + if (*src_it != *target_it) { + meas_obj_t* added_obj = meascfg_add_meas_obj(&meas_cfg, *target_it); + // Add cells if there were changes. + compute_diff_cells(src_it->meas_obj.meas_obj_eutra(), target_it->meas_obj.meas_obj_eutra(), added_obj); + } + }; + srslte::compute_cfg_diff( + prev_cfg.meas_obj_to_add_mod_list, target_cfg.meas_obj_to_add_mod_list, rem_func, add_func, mod_func); + meas_cfg.meas_obj_to_add_mod_list_present = meas_cfg.meas_obj_to_add_mod_list.size() > 0; + meas_cfg.meas_obj_to_rem_list_present = meas_cfg.meas_obj_to_rem_list.size() > 0; + // TODO: black cells and white cells +} + +/*********************************** + * reportToAddModList + **********************************/ + +report_cfg_to_add_mod_s* add_report_cfg(report_cfg_list& list, const report_cfg_eutra_s& reportcfg) +{ + report_cfg_to_add_mod_s new_rep; + new_rep.report_cfg_id = srslte::find_rrc_obj_id_gap(list); + new_rep.report_cfg.set_report_cfg_eutra() = reportcfg; + + return srslte::add_rrc_obj(list, new_rep); +} + +/** + * TS 36.331 - Section 5.5.2.6/7 - Reporting configuration removal and addition/modification + */ +void compute_diff_report_cfgs(const meas_cfg_s& src_cfg, const meas_cfg_s& target_cfg, meas_cfg_s& meas_cfg) +{ + srslte::compute_cfg_diff(src_cfg.report_cfg_to_add_mod_list, + target_cfg.report_cfg_to_add_mod_list, + meas_cfg.report_cfg_to_add_mod_list, + meas_cfg.report_cfg_to_rem_list); + meas_cfg.report_cfg_to_add_mod_list_present = meas_cfg.report_cfg_to_add_mod_list.size() > 0; + meas_cfg.report_cfg_to_rem_list_present = meas_cfg.report_cfg_to_rem_list.size() > 0; +} + +meas_id_to_add_mod_s* add_measid_cfg(meas_id_to_add_mod_list_l& meas_id_list, uint8_t measobjid, uint8_t measrepid) +{ + meas_id_to_add_mod_s new_measid; + new_measid.report_cfg_id = measrepid; + new_measid.meas_obj_id = measobjid; + new_measid.meas_id = srslte::find_rrc_obj_id_gap(meas_id_list); + return srslte::add_rrc_obj(meas_id_list, new_measid); +} + +void compute_diff_meas_ids(const meas_cfg_s& src_cfg, const meas_cfg_s& target_cfg, meas_cfg_s& meas_cfg) +{ + srslte::compute_cfg_diff(src_cfg.meas_id_to_add_mod_list, + target_cfg.meas_id_to_add_mod_list, + meas_cfg.meas_id_to_add_mod_list, + meas_cfg.meas_id_to_rem_list); + meas_cfg.meas_id_to_add_mod_list_present = meas_cfg.meas_id_to_add_mod_list.size() > 0; + meas_cfg.meas_id_to_rem_list_present = meas_cfg.meas_id_to_rem_list.size() > 0; +} + +meas_gap_cfg_c make_measgap(const meas_obj_list& measobjs, const cell_ctxt_dedicated& pcell) +{ + meas_gap_cfg_c meas_gap; + if (measobjs.size() == 1) { + // only add measGaps if PCell is not the only frequency to measure + return meas_gap; + } + switch (pcell.cell_common->cell_cfg.meas_cfg.meas_gap_period) { + case 40: + meas_gap.set_setup().gap_offset.set_gp0() = pcell.meas_gap_offset; + break; + case 80: + meas_gap.set_setup().gap_offset.set_gp1() = pcell.meas_gap_offset; + break; + case 0: // no meas gaps configured + break; + default: + srslte::logmap::get("RRC")->error("Error setting measurement gap.\n"); + } + return meas_gap; +} + +/*********************************** + * measConfig + **********************************/ + +bool set_meascfg_presence_flags(meas_cfg_s& meascfg) +{ + meascfg.meas_obj_to_add_mod_list_present = meascfg.meas_obj_to_add_mod_list.size() > 0; + meascfg.meas_obj_to_rem_list_present = meascfg.meas_obj_to_rem_list.size() > 0; + meascfg.report_cfg_to_add_mod_list_present = meascfg.report_cfg_to_add_mod_list.size() > 0; + meascfg.report_cfg_to_rem_list_present = meascfg.report_cfg_to_rem_list.size() > 0; + meascfg.meas_id_to_add_mod_list_present = meascfg.meas_id_to_add_mod_list.size() > 0; + meascfg.meas_id_to_rem_list_present = meascfg.meas_id_to_rem_list.size() > 0; + meascfg.quant_cfg_present = meascfg.quant_cfg.quant_cfg_eutra_present; + meascfg.meas_gap_cfg_present = meascfg.meas_gap_cfg.type().value != setup_opts::nulltype; + + return meascfg.meas_obj_to_add_mod_list_present or meascfg.meas_obj_to_rem_list_present or + meascfg.report_cfg_to_add_mod_list_present or meascfg.report_cfg_to_rem_list_present or + meascfg.meas_id_to_add_mod_list_present or meascfg.meas_id_to_rem_list_present or meascfg.quant_cfg_present or + meascfg.meas_gap_cfg_present; +} + +bool fill_meascfg_enb_cfg(meas_cfg_s& meascfg, const cell_ctxt_dedicated_list& ue_cell_list) +{ + const cell_ctxt_dedicated* pcell = ue_cell_list.get_ue_cc_idx(UE_PCELL_CC_IDX); + assert(pcell != nullptr); + const cell_info_common* pcell_cfg = pcell->cell_common; + const auto& pcell_meascfg = pcell_cfg->cell_cfg.meas_cfg; + + // Add PCell+Scells to measObjToAddModList + for (uint32_t ue_cc_idx = 0; ue_cc_idx < ue_cell_list.nof_cells(); ++ue_cc_idx) { + const auto* cell = ue_cell_list.get_ue_cc_idx(ue_cc_idx); + add_meas_obj(meascfg.meas_obj_to_add_mod_list, cell->get_dl_earfcn()); + } + + // Inserts all cells in meas_cell_list that are not PCell or SCells + for (const meas_cell_cfg_t& meascell : pcell_meascfg.meas_cells) { + if (ue_cell_list.find_cell(meascell.earfcn, meascell.pci) == nullptr) { + add_cell_enb_cfg(meascfg.meas_obj_to_add_mod_list, meascell); + } + } + + // Insert report cfg of PCell + for (const report_cfg_eutra_s& reportcfg : pcell_meascfg.meas_reports) { + add_report_cfg(meascfg.report_cfg_to_add_mod_list, reportcfg); + } + + // Insert quantity config + meascfg.quant_cfg.quant_cfg_eutra_present = true; + meascfg.quant_cfg.quant_cfg_eutra = pcell_meascfg.quant_cfg; + + // Insert all measIds + // TODO: add this to the parser + if (meascfg.report_cfg_to_add_mod_list.size() > 0) { + for (const auto& measobj : meascfg.meas_obj_to_add_mod_list) { + add_measid_cfg( + meascfg.meas_id_to_add_mod_list, measobj.meas_obj_id, meascfg.report_cfg_to_add_mod_list[0].report_cfg_id); + } + } + + // Set MeasGap + meascfg.meas_gap_cfg = make_measgap(meascfg.meas_obj_to_add_mod_list, *pcell); + + return set_meascfg_presence_flags(meascfg); +} + +bool compute_diff_meascfg(const meas_cfg_s& current_meascfg, const meas_cfg_s& target_meascfg, meas_cfg_s& diff_meascfg) +{ + diff_meascfg = {}; + compute_diff_meas_objs(current_meascfg, target_meascfg, diff_meascfg); + compute_diff_report_cfgs(current_meascfg, target_meascfg, diff_meascfg); + compute_diff_meas_ids(current_meascfg, target_meascfg, diff_meascfg); + if (target_meascfg.quant_cfg_present != current_meascfg.quant_cfg_present or + (target_meascfg.quant_cfg_present and target_meascfg.quant_cfg != current_meascfg.quant_cfg)) { + diff_meascfg.quant_cfg = target_meascfg.quant_cfg; + } + + // Only update measGap if it was not set before or periodicity changed + if (current_meascfg.meas_gap_cfg.type().value == setup_opts::setup) { + if (target_meascfg.meas_gap_cfg.type().value != setup_opts::setup) { + diff_meascfg.meas_gap_cfg.set(setup_opts::release); + } else if (target_meascfg.meas_gap_cfg.setup().gap_offset.type() != + current_meascfg.meas_gap_cfg.setup().gap_offset.type()) { + diff_meascfg.meas_gap_cfg = target_meascfg.meas_gap_cfg; + } + } else { + diff_meascfg.meas_gap_cfg = target_meascfg.meas_gap_cfg; + } + + return set_meascfg_presence_flags(diff_meascfg); +} + +bool apply_meascfg_updates(meas_cfg_s& meascfg, + meas_cfg_s& current_meascfg, + const cell_ctxt_dedicated_list& ue_cell_list, + int prev_pci) +{ + meascfg = {}; + + const cell_ctxt_dedicated* pcell = ue_cell_list.get_ue_cc_idx(UE_PCELL_CC_IDX); + uint32_t prev_earfcn = 0, target_earfcn = pcell->get_dl_earfcn(); + if (current_meascfg.meas_obj_to_add_mod_list_present) { + prev_earfcn = get_earfcn(current_meascfg.meas_obj_to_add_mod_list[0]); + } + + if (static_cast(prev_pci) == pcell->get_pci() and prev_earfcn == target_earfcn) { + // Shortcut: No PCell change -> no measConfig updates + return false; + } + + // Apply TS 36.331 5.5.6.1 - If Source and Target eNB EARFCNs do no match, update SourceMeasCfg.MeasIdList + if (prev_earfcn != target_earfcn) { + meas_obj_t* found_target_obj = find_meas_obj(current_meascfg.meas_obj_to_add_mod_list, target_earfcn); + meas_obj_t* found_src_obj = prev_earfcn != 0 ? ¤t_meascfg.meas_obj_to_add_mod_list[0] : nullptr; + if (found_target_obj != nullptr and found_src_obj != nullptr) { + for (auto& mid : current_meascfg.meas_id_to_add_mod_list) { + if (found_target_obj->meas_obj_id == mid.meas_obj_id) { + mid.meas_obj_id = found_src_obj->meas_obj_id; + } else if (found_src_obj->meas_obj_id == mid.meas_obj_id) { + mid.meas_obj_id = found_target_obj->meas_obj_id; + } + } + } else if (found_src_obj != nullptr) { + for (auto it = current_meascfg.meas_id_to_add_mod_list.begin(); + it != current_meascfg.meas_id_to_add_mod_list.end();) { + if (it->meas_obj_id == found_src_obj->meas_obj_id) { + auto rit = it++; + current_meascfg.meas_id_to_add_mod_list.erase(rit); + } else { + ++it; + } + } + } + } + + // Generate final measConfig + meas_cfg_s target_meascfg; + fill_meascfg_enb_cfg(target_meascfg, ue_cell_list); + + // Set a MeasConfig in the RRC Connection Reconfiguration for HO. + compute_diff_meas_objs(current_meascfg, target_meascfg, meascfg); + compute_diff_report_cfgs(current_meascfg, target_meascfg, meascfg); + compute_diff_meas_ids(current_meascfg, target_meascfg, meascfg); + if (target_meascfg.quant_cfg_present != current_meascfg.quant_cfg_present or + (target_meascfg.quant_cfg_present and target_meascfg.quant_cfg != current_meascfg.quant_cfg)) { + meascfg.quant_cfg = target_meascfg.quant_cfg; + } + // Only update measGap if it was not set before or periodicity changed + if (current_meascfg.meas_gap_cfg.type().value == setup_opts::setup) { + if (target_meascfg.meas_gap_cfg.type().value != setup_opts::setup) { + meascfg.meas_gap_cfg.set(setup_opts::release); + } else if (target_meascfg.meas_gap_cfg.setup().gap_offset.type() != + current_meascfg.meas_gap_cfg.setup().gap_offset.type()) { + meascfg.meas_gap_cfg = target_meascfg.meas_gap_cfg; + } + } else { + meascfg.meas_gap_cfg = target_meascfg.meas_gap_cfg; + } + + // Update current measconfig + bool ret = set_meascfg_presence_flags(meascfg); + current_meascfg = target_meascfg; + + return ret; +} + +} // namespace srsenb diff --git a/srsenb/src/stack/rrc/ue_rr_cfg.cc b/srsenb/src/stack/rrc/ue_rr_cfg.cc index 5f60fff20..3dc35a4cf 100644 --- a/srsenb/src/stack/rrc/ue_rr_cfg.cc +++ b/srsenb/src/stack/rrc/ue_rr_cfg.cc @@ -38,8 +38,6 @@ using namespace asn1::rrc; namespace srsenb { -srslte::log_ref log_h = srslte::logmap::get("RRC"); - /****************************** * SRBs / DRBs *****************************/ @@ -47,7 +45,7 @@ srslte::log_ref log_h = srslte::logmap::get("RRC"); srb_to_add_mod_s* add_srb(srb_to_add_mod_list_l& srbs, uint8_t srb_id) { if (srb_id > 2 or srb_id == 0) { - log_h->error("Invalid SRB id=%d\n", srb_id); + srslte::logmap::get("RRC")->error("Invalid SRB id=%d\n", srb_id); return nullptr; } @@ -116,7 +114,7 @@ int16_t get_ri(uint32_t m_ri) ri_idx = 805 - N_offset_ri; break; default: - log_h->error("Allocating RI: invalid m_ri=%d\n", m_ri); + srslte::logmap::get("RRC")->error("Allocating RI: invalid m_ri=%d\n", m_ri); return -1; } @@ -148,7 +146,7 @@ int fill_cqi_report_setup(cqi_report_cfg_s& cqi_rep, if (cqi_rep.cqi_report_periodic_present) { const cell_ctxt_dedicated* pcell = ue_cell_list.get_ue_cc_idx(UE_PCELL_CC_IDX); if (pcell == nullptr or not pcell->cqi_res_present) { - log_h->warning("PCell CQI resources haven\'t been allocated yet\n"); + srslte::logmap::get("RRC")->warning("PCell CQI resources haven\'t been allocated yet\n"); return SRSLTE_ERROR; } auto& cqi_periodic = cqi_rep.cqi_report_periodic.setup(); @@ -188,7 +186,7 @@ void fill_cqi_report_reconf(cqi_report_cfg_s& cqi_rep, cqi_setup.ri_cfg_idx_present = true; cqi_setup.ri_cfg_idx = ri_idx; } else { - log_h->warning("Warning: Configured wrong M_ri parameter.\n"); + srslte::logmap::get("RRC")->warning("Warning: Configured wrong M_ri parameter.\n"); } } } @@ -566,45 +564,9 @@ void apply_scells_to_add_diff(asn1::rrc::scell_to_add_mod_list_r10_l& current_sc } } -bool apply_measgap_updates(meas_gap_cfg_c& meas_gaps, - meas_gap_cfg_c& current_meas_gaps, - const cell_ctxt_dedicated_list& ue_cell_list) -{ - bool flag_set = false; - const cell_ctxt_dedicated* pcell = ue_cell_list.get_ue_cc_idx(UE_PCELL_CC_IDX); - - meas_gap_cfg_c target_meas_gap; - switch (pcell->cell_common->cell_cfg.meas_cfg.meas_gap_period) { - case 40: - target_meas_gap.set_setup().gap_offset.set_gp0() = pcell->meas_gap_offset; - break; - case 80: - target_meas_gap.set_setup().gap_offset.set_gp1() = pcell->meas_gap_offset; - break; - case 0: // no meas gaps - break; - default: - log_h->error("Error setting measurement gaps\n"); - } - - bool is_current_setup = current_meas_gaps.type().value == setup_opts::setup; - bool is_target_setup = target_meas_gap.type().value == setup_opts::setup; - if (is_target_setup) { - if (not is_current_setup or - current_meas_gaps.setup().gap_offset.type() != target_meas_gap.setup().gap_offset.type()) { - meas_gaps = target_meas_gap; - flag_set = true; - } - } else if (is_current_setup) { - meas_gaps.set(setup_opts::release); - flag_set = true; - } - - // update meas gaps - current_meas_gaps = target_meas_gap; - - return flag_set; -} +/*********************************** + * measConfig + **********************************/ /// Apply Reconf updates and update current state void apply_reconf_updates(asn1::rrc::rrc_conn_recfg_r8_ies_s& recfg_r8, @@ -620,8 +582,6 @@ void apply_reconf_updates(asn1::rrc::rrc_conn_recfg_r8_ies_s& recfg_r8, fill_rr_cfg_ded_reconf( recfg_r8.rr_cfg_ded, current_ue_cfg.rr_cfg, enb_cfg, ue_cell_list, bearers, ue_caps, phy_cfg_updated); fill_scells_reconf(recfg_r8, current_ue_cfg.scells, enb_cfg, ue_cell_list, ue_caps); - recfg_r8.meas_cfg.meas_gap_cfg_present = - apply_measgap_updates(recfg_r8.meas_cfg.meas_gap_cfg, current_ue_cfg.meas_gaps, ue_cell_list); recfg_r8.meas_cfg_present |= recfg_r8.meas_cfg.meas_gap_cfg_present; // Add pending NAS info diff --git a/srsenb/test/upper/CMakeLists.txt b/srsenb/test/upper/CMakeLists.txt index 1b54eacad..0f66a0e45 100644 --- a/srsenb/test/upper/CMakeLists.txt +++ b/srsenb/test/upper/CMakeLists.txt @@ -18,15 +18,22 @@ # and at http://www.gnu.org/licenses/. # +add_library(test_helpers test_helpers.cc) +target_link_libraries(test_helpers srsenb_rrc rrc_asn1 s1ap_asn1 srslte_common enb_cfg_parser ${LIBCONFIGPP_LIBRARIES}) + # Simple PLMN -> MCC/MNC test add_executable(plmn_test plmn_test.cc) target_link_libraries(plmn_test rrc_asn1) add_executable(rrc_mobility_test rrc_mobility_test.cc) -target_link_libraries(rrc_mobility_test srsenb_rrc rrc_asn1 s1ap_asn1 srslte_common srslte_asn1 enb_cfg_parser ${LIBCONFIGPP_LIBRARIES}) +target_link_libraries(rrc_mobility_test srsenb_rrc rrc_asn1 s1ap_asn1 srslte_common srslte_asn1 enb_cfg_parser test_helpers ${LIBCONFIGPP_LIBRARIES}) add_executable(erab_setup_test erab_setup_test.cc) -target_link_libraries(erab_setup_test srsenb_rrc rrc_asn1 s1ap_asn1 srslte_common srslte_asn1 enb_cfg_parser ${LIBCONFIGPP_LIBRARIES}) +target_link_libraries(erab_setup_test srsenb_rrc rrc_asn1 s1ap_asn1 srslte_common srslte_asn1 enb_cfg_parser test_helpers ${LIBCONFIGPP_LIBRARIES}) + +add_executable(rrc_meascfg_test rrc_meascfg_test.cc) +target_link_libraries(rrc_meascfg_test test_helpers) +add_test(rrc_meascfg_test rrc_meascfg_test) add_test(rrc_mobility_test rrc_mobility_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..) add_test(erab_setup_test erab_setup_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..) diff --git a/srsenb/test/upper/rrc_meascfg_test.cc b/srsenb/test/upper/rrc_meascfg_test.cc new file mode 100644 index 000000000..5abf398b1 --- /dev/null +++ b/srsenb/test/upper/rrc_meascfg_test.cc @@ -0,0 +1,298 @@ +/* + * Copyright 2013-2020 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/enb.h" +#include "srsenb/hdr/stack/rrc/ue_meas_cfg.h" +#include "srslte/common/test_common.h" +#include "srslte/interfaces/enb_rrc_interface_types.h" +#include "test_helpers.h" + +using namespace asn1::rrc; + +namespace srsenb { + +/** + * Checks if measObjs and reportConfigs are correctly added to the ASN1 RRC measConfig. Current checks: + * - avoids repeated earfcns in the measObjsToAddModList + * - avoids repeated PCIs in the CellsToAddModList of same earfcn + * - measObjId, cellIdx, reportConfigId, measId are kept in order + * @return error code + */ +int test_correct_meascfg_insertion() +{ + meas_cell_cfg_t cell1 = generate_cell1(), cell2{}, cell3{}, cell4{}; + cell2 = cell1; + cell2.pci = 2; + cell2.eci = 0x19C02; + cell3 = cell1; + cell3.earfcn = 2850; + cell4 = cell1; + cell4.q_offset = 1; + + report_cfg_eutra_s rep1 = generate_rep1(); + + // TEST 1: cell/rep insertion in empty MeasCfg + { + meas_cfg_s meas_cfg{}; + const auto& objs = meas_cfg.meas_obj_to_add_mod_list; + auto ret = add_cell_enb_cfg(meas_cfg.meas_obj_to_add_mod_list, cell1); + TESTASSERT(std::get<0>(ret) and std::get<1>(ret) != nullptr); + TESTASSERT(objs.size() == 1 and objs[0].meas_obj_id == 1); + TESTASSERT(objs[0].meas_obj.type().value == + asn1::rrc::meas_obj_to_add_mod_s::meas_obj_c_::types_opts::meas_obj_eutra); + auto& eutra = objs[0].meas_obj.meas_obj_eutra(); + TESTASSERT(eutra.carrier_freq == cell1.earfcn); + TESTASSERT(eutra.cells_to_add_mod_list.size() == 1); + TESTASSERT(is_cell_cfg_equal(cell1, eutra.cells_to_add_mod_list[0])); + + auto* ret2 = add_report_cfg(meas_cfg.report_cfg_to_add_mod_list, rep1); + TESTASSERT(ret2->report_cfg_id == 1); + TESTASSERT(ret2->report_cfg.report_cfg_eutra() == rep1); + } + + { + meas_cfg_s meas_cfg{}; + const auto& objs = meas_cfg.meas_obj_to_add_mod_list; + + // TEST 2: insertion of out-of-order cell ids in same earfcn + add_cell_enb_cfg(meas_cfg.meas_obj_to_add_mod_list, cell2); + add_cell_enb_cfg(meas_cfg.meas_obj_to_add_mod_list, cell1); + TESTASSERT(objs.size() == 1 and objs[0].meas_obj_id == 1); + auto& eutra = objs[0].meas_obj.meas_obj_eutra(); + TESTASSERT(eutra.carrier_freq == cell1.earfcn); + TESTASSERT(eutra.cells_to_add_mod_list.size() == 2); + const cells_to_add_mod_s* cell_it = eutra.cells_to_add_mod_list.begin(); + TESTASSERT(cell_it[0].cell_idx == 1); + TESTASSERT(cell_it[1].cell_idx == 2); + TESTASSERT(cell_it[0].pci == cell2.pci); + TESTASSERT(cell_it[1].pci == cell1.pci); + + // TEST 3: insertion of cell in another frequency + auto ret1 = add_cell_enb_cfg(meas_cfg.meas_obj_to_add_mod_list, cell3); + TESTASSERT(std::get<0>(ret1) and std::get<1>(ret1)->meas_obj_id == 2); + TESTASSERT(objs.size() == 2 and objs[1].meas_obj_id == 2); + const auto& eutra2 = objs[1].meas_obj.meas_obj_eutra(); + TESTASSERT(eutra2.carrier_freq == cell3.earfcn); + TESTASSERT(eutra2.cells_to_add_mod_list_present and eutra2.cells_to_add_mod_list.size() == 1); + TESTASSERT(eutra2.cells_to_add_mod_list[0].cell_idx == 1); + TESTASSERT(eutra2.cells_to_add_mod_list[0].pci == cell3.pci); + + // TEST 4 : update of existing cell + auto ret2 = add_cell_enb_cfg(meas_cfg.meas_obj_to_add_mod_list, cell4); + TESTASSERT(std::get<0>(ret2) and std::get<1>(ret2)->meas_obj_id == 1); + auto& eutra3 = objs[0].meas_obj.meas_obj_eutra(); + TESTASSERT(objs.size() == 2 and objs[0].meas_obj_id == 1); + TESTASSERT(eutra3.carrier_freq == cell4.earfcn); + TESTASSERT(eutra3.cells_to_add_mod_list.size() == 2); + TESTASSERT(eutra3.cells_to_add_mod_list[1].cell_idx == 2); + TESTASSERT(eutra3.cells_to_add_mod_list[1].pci == cell4.pci); + TESTASSERT(eutra3.cells_to_add_mod_list[1].cell_individual_offset.to_number() == 1); + } + + return 0; +} + +int test_correct_meascfg_calculation() +{ + meas_cfg_s src_var{}, target_var{}; + + meas_cell_cfg_t cell1{}, cell2{}; + cell1.earfcn = 3400; + cell1.pci = 1; + cell1.q_offset = 0; + cell1.eci = 0x19C01; + cell2 = cell1; + cell2.pci = 2; + cell2.eci = 0x19C02; + + report_cfg_eutra_s rep1 = generate_rep1(), rep2{}, rep3{}; + rep2 = rep1; + rep2.trigger_quant.value = report_cfg_eutra_s::trigger_quant_opts::rsrq; + rep3 = rep2; + rep3.report_quant.value = report_cfg_eutra_s::report_quant_opts::same_as_trigger_quant; + + { + meas_cfg_s result_meascfg; + + // TEST 1: Insertion of two cells in target meas_cfg_s propagates to the diff meas_cfg_s + add_cell_enb_cfg(target_var.meas_obj_to_add_mod_list, cell1); + add_cell_enb_cfg(target_var.meas_obj_to_add_mod_list, cell2); + add_report_cfg(target_var.report_cfg_to_add_mod_list, rep1); + add_report_cfg(target_var.report_cfg_to_add_mod_list, rep2); + add_measid_cfg(target_var.meas_id_to_add_mod_list, 1, 1); + add_measid_cfg(target_var.meas_id_to_add_mod_list, 1, 2); + TESTASSERT(compute_diff_meascfg(src_var, target_var, result_meascfg)); + TESTASSERT(result_meascfg.meas_obj_to_add_mod_list_present); + TESTASSERT(not result_meascfg.meas_obj_to_rem_list_present); + TESTASSERT(result_meascfg.meas_obj_to_add_mod_list.size() == 1); + auto* item = &result_meascfg.meas_obj_to_add_mod_list[0]; + TESTASSERT(item->meas_obj_id == 1 and + item->meas_obj.type().value == meas_obj_to_add_mod_s::meas_obj_c_::types_opts::meas_obj_eutra); + auto& eutra = item->meas_obj.meas_obj_eutra(); + TESTASSERT(eutra.cells_to_add_mod_list_present and not eutra.cells_to_rem_list_present); + TESTASSERT(eutra.cells_to_add_mod_list.size() == 2); + auto* cell_item = &eutra.cells_to_add_mod_list[0]; + TESTASSERT(is_cell_cfg_equal(cell1, *cell_item)); + cell_item++; + TESTASSERT(is_cell_cfg_equal(cell2, *cell_item)); + TESTASSERT(result_meascfg.report_cfg_to_add_mod_list_present and not result_meascfg.report_cfg_to_rem_list_present); + TESTASSERT(result_meascfg.report_cfg_to_add_mod_list.size() == 2); + TESTASSERT(result_meascfg.report_cfg_to_add_mod_list[0].report_cfg_id == 1); + TESTASSERT(result_meascfg.report_cfg_to_add_mod_list[0].report_cfg.report_cfg_eutra() == rep1); + TESTASSERT(result_meascfg.report_cfg_to_add_mod_list[1].report_cfg_id == 2); + TESTASSERT(result_meascfg.report_cfg_to_add_mod_list[1].report_cfg.report_cfg_eutra() == rep2); + TESTASSERT(result_meascfg.meas_id_to_add_mod_list_present and not result_meascfg.meas_id_to_rem_list_present); + TESTASSERT(result_meascfg.meas_id_to_add_mod_list.size() == 2); + auto* measid_item = &result_meascfg.meas_id_to_add_mod_list[0]; + TESTASSERT(measid_item->meas_id == 1 and measid_item->meas_obj_id == 1 and measid_item->report_cfg_id == 1); + measid_item++; + TESTASSERT(measid_item->meas_id == 2 and measid_item->meas_obj_id == 1 and measid_item->report_cfg_id == 2); + + // TEST 2: measConfig is empty if nothing was updated + src_var = target_var; + TESTASSERT(not compute_diff_meascfg(src_var, target_var, result_meascfg)); + TESTASSERT(not result_meascfg.meas_obj_to_add_mod_list_present and not result_meascfg.meas_obj_to_rem_list_present); + TESTASSERT(result_meascfg.meas_obj_to_add_mod_list.size() == 0); + TESTASSERT(not result_meascfg.report_cfg_to_add_mod_list_present and + not result_meascfg.report_cfg_to_rem_list_present); + TESTASSERT(result_meascfg.report_cfg_to_add_mod_list.size() == 0); + + // TEST 3: Cell is added to cellsToAddModList if just a field was updated + cell1.q_offset = 5; + src_var = target_var; + add_cell_enb_cfg(target_var.meas_obj_to_add_mod_list, cell1); + TESTASSERT(compute_diff_meascfg(src_var, target_var, result_meascfg)); + TESTASSERT(result_meascfg.meas_obj_to_add_mod_list_present); + TESTASSERT(result_meascfg.meas_obj_to_add_mod_list.size() == 1); + item = &result_meascfg.meas_obj_to_add_mod_list[0]; + TESTASSERT(item->meas_obj_id == 1 and + item->meas_obj.type().value == meas_obj_to_add_mod_s::meas_obj_c_::types_opts::meas_obj_eutra); + eutra = item->meas_obj.meas_obj_eutra(); + TESTASSERT(eutra.cells_to_add_mod_list_present and not eutra.cells_to_rem_list_present); + TESTASSERT(eutra.cells_to_add_mod_list.size() == 1); + cell_item = &eutra.cells_to_add_mod_list[0]; + TESTASSERT(is_cell_cfg_equal(cell1, *cell_item)); + + // TEST 4: Removal of cell/rep from target propagates to the resulting meas_cfg_s + src_var = target_var; + const auto& src_measobjs = src_var.meas_obj_to_add_mod_list; + TESTASSERT(src_measobjs.size() == 1); + TESTASSERT(src_measobjs[0].meas_obj.meas_obj_eutra().cells_to_add_mod_list.size() == 2); + target_var = {}; + add_cell_enb_cfg(target_var.meas_obj_to_add_mod_list, cell2); + add_report_cfg(target_var.report_cfg_to_add_mod_list, rep1); + add_report_cfg(target_var.report_cfg_to_add_mod_list, rep3); + TESTASSERT(compute_diff_meascfg(src_var, target_var, result_meascfg)); + TESTASSERT(result_meascfg.meas_obj_to_add_mod_list_present); + TESTASSERT(result_meascfg.meas_obj_to_add_mod_list.size() == 1); + item = &result_meascfg.meas_obj_to_add_mod_list[0]; + TESTASSERT(item->meas_obj_id == 1 and + item->meas_obj.type().value == meas_obj_to_add_mod_s::meas_obj_c_::types_opts::meas_obj_eutra); + eutra = item->meas_obj.meas_obj_eutra(); + TESTASSERT(eutra.cells_to_add_mod_list_present and eutra.cells_to_add_mod_list.size() == 1); + TESTASSERT(eutra.cells_to_add_mod_list[0].pci == cell2.pci); + TESTASSERT(eutra.cells_to_rem_list_present and eutra.cells_to_rem_list.size() == 1); + TESTASSERT(eutra.cells_to_rem_list[0] == 2); + TESTASSERT(result_meascfg.report_cfg_to_add_mod_list_present and not result_meascfg.report_cfg_to_rem_list_present); + TESTASSERT(result_meascfg.report_cfg_to_add_mod_list.size() == 1); + TESTASSERT(result_meascfg.report_cfg_to_add_mod_list[0].report_cfg_id == 2); + TESTASSERT(result_meascfg.report_cfg_to_add_mod_list[0].report_cfg.report_cfg_eutra() == rep3); + } + + { + // TEST: creation of a meas_cfg using the srsenb::rrc_cfg_t + rrc_cfg_t cfg; + srsenb::all_args_t all_args; + TESTASSERT(test_helpers::parse_default_cfg(&cfg, all_args) == SRSLTE_SUCCESS); + cfg.enb_id = 0x19B; + cfg.cell.nof_prb = 6; + cfg.meas_cfg_present = true; + cfg.cell_list.resize(2); + cfg.cell_list[0].dl_earfcn = 2850; + cfg.cell_list[0].cell_id = 0x01; + cfg.cell_list[0].scell_list.resize(1); + cfg.cell_list[0].scell_list[0].cell_id = 0x02; + cfg.cell_list[0].meas_cfg.meas_cells.resize(1); + cfg.cell_list[0].meas_cfg.meas_cells[0] = generate_cell1(); + cfg.cell_list[0].meas_cfg.meas_cells[0].pci = 3; + cfg.cell_list[1].dl_earfcn = 3400; + cfg.cell_list[1].cell_id = 0x02; + cfg.cell_list[0].meas_cfg.meas_reports.resize(1); + cfg.cell_list[0].meas_cfg.meas_reports[0] = generate_rep1(); + + // TEST: correct construction of list of cells + cell_info_common_list cell_list{cfg}; + TESTASSERT(cell_list.nof_cells() == 2); + TESTASSERT(cell_list.get_cc_idx(0)->scells.size() == 1); + TESTASSERT(cell_list.get_cc_idx(0)->scells[0] == cell_list.get_cc_idx(1)); + TESTASSERT(cell_list.get_cc_idx(1)->scells.empty()); + freq_res_common_list freq_res{cfg}; + + // measConfig only includes earfcns of active carriers for a given pcell + meas_cfg_s cell_meas_cfg; + cell_ctxt_dedicated_list ue_cell_list{cfg, freq_res, cell_list}; + ue_cell_list.set_cells({0}); + TESTASSERT(fill_meascfg_enb_cfg(cell_meas_cfg, ue_cell_list)); + const auto& measobjs = cell_meas_cfg.meas_obj_to_add_mod_list; + TESTASSERT(measobjs.size() == 2); + TESTASSERT(measobjs[0].meas_obj.meas_obj_eutra().carrier_freq == 2850); + TESTASSERT(not measobjs[0].meas_obj.meas_obj_eutra().cells_to_add_mod_list_present); + TESTASSERT(measobjs[1].meas_obj.meas_obj_eutra().carrier_freq == 3400); + TESTASSERT(measobjs[1].meas_obj.meas_obj_eutra().cells_to_add_mod_list_present); + TESTASSERT(measobjs[1].meas_obj.meas_obj_eutra().cells_to_add_mod_list.size() == 1); + TESTASSERT(measobjs[1].meas_obj.meas_obj_eutra().cells_to_add_mod_list[0].pci == 3); + TESTASSERT(cell_meas_cfg.report_cfg_to_add_mod_list_present); + TESTASSERT(cell_meas_cfg.report_cfg_to_add_mod_list.size() == 1); + TESTASSERT(cell_meas_cfg.report_cfg_to_add_mod_list[0].report_cfg.report_cfg_eutra() == + cfg.cell_list[0].meas_cfg.meas_reports[0]); + TESTASSERT(cell_meas_cfg.meas_id_to_add_mod_list_present); + const auto& measid = cell_meas_cfg.meas_id_to_add_mod_list[0]; + TESTASSERT(measid.meas_id == 1 and measid.meas_obj_id == 1 and measid.report_cfg_id == 1); + + meas_cfg_s cell_meas_cfg2; + ue_cell_list.set_cells({1}); + TESTASSERT(fill_meascfg_enb_cfg(cell_meas_cfg2, ue_cell_list)); + const auto& measobjs2 = cell_meas_cfg2.meas_obj_to_add_mod_list; + TESTASSERT(measobjs2.size() == 1); + TESTASSERT(measobjs2[0].meas_obj.meas_obj_eutra().carrier_freq == 3400); + TESTASSERT(not measobjs2[0].meas_obj.meas_obj_eutra().cells_to_add_mod_list_present); + } + + return SRSLTE_SUCCESS; +} + +} // namespace srsenb + +int main(int argc, char** argv) +{ + srslte::logmap::set_default_log_level(srslte::LOG_LEVEL_INFO); + + if (argc < 3) { + argparse::usage(argv[0]); + return -1; + } + argparse::parse_args(argc, argv); + TESTASSERT(test_correct_meascfg_insertion() == 0); + TESTASSERT(test_correct_meascfg_calculation() == 0); + srslte::console("Success\n"); + + return 0; +} diff --git a/srsenb/test/upper/rrc_mobility_test.cc b/srsenb/test/upper/rrc_mobility_test.cc index a4d2bd454..b3c42edae 100644 --- a/srsenb/test/upper/rrc_mobility_test.cc +++ b/srsenb/test/upper/rrc_mobility_test.cc @@ -30,253 +30,6 @@ using namespace asn1::rrc; -meas_cell_cfg_t generate_cell1() -{ - meas_cell_cfg_t cell1{}; - cell1.earfcn = 3400; - cell1.pci = 1; - cell1.q_offset = 0; - cell1.eci = 0x19C01; - return cell1; -} - -report_cfg_eutra_s generate_rep1() -{ - report_cfg_eutra_s rep{}; - rep.report_amount.value = report_cfg_eutra_s::report_amount_opts::r16; - rep.report_interv.value = report_interv_opts::ms240; - rep.max_report_cells = 2; - rep.report_quant.value = report_cfg_eutra_s::report_quant_opts::both; - rep.trigger_quant.value = report_cfg_eutra_s::trigger_quant_opts::rsrp; - rep.trigger_type.set_event().event_id.set_event_a3(); - rep.trigger_type.event().time_to_trigger.value = time_to_trigger_opts::ms100; - rep.trigger_type.event().hysteresis = 0; - rep.trigger_type.event().event_id.event_a3().a3_offset = 5; - rep.trigger_type.event().event_id.event_a3().report_on_leave = true; - return rep; -} - -bool is_cell_cfg_equal(const meas_cell_cfg_t& cfg, const cells_to_add_mod_s& cell) -{ - return cfg.pci == cell.pci and cell.cell_individual_offset.to_number() == (int8_t)round(cfg.q_offset); -} - -int test_correct_insertion() -{ - meas_cell_cfg_t cell1 = generate_cell1(), cell2{}, cell3{}, cell4{}; - cell2 = cell1; - cell2.pci = 2; - cell2.eci = 0x19C02; - cell3 = cell1; - cell3.earfcn = 2850; - cell4 = cell1; - cell4.q_offset = 1; - - report_cfg_eutra_s rep1 = generate_rep1(); - - // TEST 1: cell/rep insertion in empty varMeasCfg - { - var_meas_cfg_t var_cfg{}; - auto ret = var_cfg.add_cell_cfg(cell1); - TESTASSERT(std::get<0>(ret) and std::get<1>(ret) != nullptr); - const auto& objs = var_cfg.meas_objs(); - TESTASSERT(objs.size() == 1 and objs[0].meas_obj_id == 1); - TESTASSERT(objs[0].meas_obj.type().value == - asn1::rrc::meas_obj_to_add_mod_s::meas_obj_c_::types_opts::meas_obj_eutra); - auto& eutra = objs[0].meas_obj.meas_obj_eutra(); - TESTASSERT(eutra.carrier_freq == cell1.earfcn); - TESTASSERT(eutra.cells_to_add_mod_list.size() == 1); - TESTASSERT(is_cell_cfg_equal(cell1, eutra.cells_to_add_mod_list[0])); - - auto ret2 = var_cfg.add_report_cfg(rep1); - TESTASSERT(ret2->report_cfg_id == 1); - TESTASSERT(ret2->report_cfg.report_cfg_eutra() == rep1); - } - - { - var_meas_cfg_t var_cfg{}; - const auto& objs = var_cfg.meas_objs(); - - // TEST 2: insertion of out-of-order cell ids in same earfcn - var_cfg.add_cell_cfg(cell2); - var_cfg.add_cell_cfg(cell1); - TESTASSERT(objs.size() == 1 and objs[0].meas_obj_id == 1); - auto& eutra = objs[0].meas_obj.meas_obj_eutra(); - TESTASSERT(eutra.carrier_freq == cell1.earfcn); - TESTASSERT(eutra.cells_to_add_mod_list.size() == 2); - const cells_to_add_mod_s* cell_it = eutra.cells_to_add_mod_list.begin(); - TESTASSERT(cell_it[0].cell_idx == 1); - TESTASSERT(cell_it[1].cell_idx == 2); - TESTASSERT(cell_it[0].pci == cell2.pci); - TESTASSERT(cell_it[1].pci == cell1.pci); - - // TEST 3: insertion of cell in another frequency - auto ret1 = var_cfg.add_cell_cfg(cell3); - TESTASSERT(std::get<0>(ret1) and std::get<1>(ret1)->meas_obj_id == 2); - TESTASSERT(objs.size() == 2 and objs[1].meas_obj_id == 2); - const auto& eutra2 = objs[1].meas_obj.meas_obj_eutra(); - TESTASSERT(eutra2.carrier_freq == cell3.earfcn); - TESTASSERT(eutra2.cells_to_add_mod_list_present and eutra2.cells_to_add_mod_list.size() == 1); - TESTASSERT(eutra2.cells_to_add_mod_list[0].cell_idx == 1); - TESTASSERT(eutra2.cells_to_add_mod_list[0].pci == cell3.pci); - - // TEST 4: update of existing cell - auto ret2 = var_cfg.add_cell_cfg(cell4); - TESTASSERT(std::get<0>(ret2) and std::get<1>(ret2)->meas_obj_id == 1); - auto& eutra3 = objs[0].meas_obj.meas_obj_eutra(); - TESTASSERT(objs.size() == 2 and objs[0].meas_obj_id == 1); - TESTASSERT(eutra3.carrier_freq == cell4.earfcn); - TESTASSERT(eutra3.cells_to_add_mod_list.size() == 2); - TESTASSERT(eutra3.cells_to_add_mod_list[1].cell_idx == 2); - TESTASSERT(eutra3.cells_to_add_mod_list[1].pci == cell4.pci); - TESTASSERT(eutra3.cells_to_add_mod_list[1].cell_individual_offset.to_number() == 1); - } - - return 0; -} - -int test_correct_meascfg_calculation() -{ - var_meas_cfg_t src_var{}, target_var{}; - - meas_cell_cfg_t cell1{}, cell2{}; - cell1.earfcn = 3400; - cell1.pci = 1; - cell1.q_offset = 0; - cell1.eci = 0x19C01; - cell2 = cell1; - cell2.pci = 2; - cell2.eci = 0x19C02; - - report_cfg_eutra_s rep1 = generate_rep1(), rep2{}, rep3{}; - rep2 = rep1; - rep2.trigger_quant.value = report_cfg_eutra_s::trigger_quant_opts::rsrq; - rep3 = rep2; - rep3.report_quant.value = report_cfg_eutra_s::report_quant_opts::same_as_trigger_quant; - - { - meas_cfg_s result_meascfg; - - // TEST 1: Insertion of two cells in var_meas propagates to the resulting meas_cfg_s cellsToAddMod list - target_var.add_cell_cfg(cell1); - target_var.add_cell_cfg(cell2); - target_var.add_report_cfg(rep1); - target_var.add_report_cfg(rep2); - target_var.add_measid_cfg(1, 1); - target_var.add_measid_cfg(1, 2); - src_var.compute_diff_meas_cfg(target_var, &result_meascfg); - TESTASSERT(result_meascfg.meas_obj_to_add_mod_list_present); - TESTASSERT(not result_meascfg.meas_obj_to_rem_list_present); - TESTASSERT(result_meascfg.meas_obj_to_add_mod_list.size() == 1); - auto* item = &result_meascfg.meas_obj_to_add_mod_list[0]; - TESTASSERT(item->meas_obj_id == 1 and - item->meas_obj.type().value == meas_obj_to_add_mod_s::meas_obj_c_::types_opts::meas_obj_eutra); - auto& eutra = item->meas_obj.meas_obj_eutra(); - TESTASSERT(eutra.cells_to_add_mod_list_present and not eutra.cells_to_rem_list_present); - TESTASSERT(eutra.cells_to_add_mod_list.size() == 2); - auto* cell_item = &eutra.cells_to_add_mod_list[0]; - TESTASSERT(is_cell_cfg_equal(cell1, *cell_item)); - cell_item++; - TESTASSERT(is_cell_cfg_equal(cell2, *cell_item)); - TESTASSERT(result_meascfg.report_cfg_to_add_mod_list_present and not result_meascfg.report_cfg_to_rem_list_present); - TESTASSERT(result_meascfg.report_cfg_to_add_mod_list.size() == 2); - TESTASSERT(result_meascfg.report_cfg_to_add_mod_list[0].report_cfg_id == 1); - TESTASSERT(result_meascfg.report_cfg_to_add_mod_list[0].report_cfg.report_cfg_eutra() == rep1); - TESTASSERT(result_meascfg.report_cfg_to_add_mod_list[1].report_cfg_id == 2); - TESTASSERT(result_meascfg.report_cfg_to_add_mod_list[1].report_cfg.report_cfg_eutra() == rep2); - TESTASSERT(result_meascfg.meas_id_to_add_mod_list_present and not result_meascfg.meas_id_to_rem_list_present); - TESTASSERT(result_meascfg.meas_id_to_add_mod_list.size() == 2); - auto* measid_item = &result_meascfg.meas_id_to_add_mod_list[0]; - TESTASSERT(measid_item->meas_id == 1 and measid_item->meas_obj_id == 1 and measid_item->report_cfg_id == 1); - measid_item++; - TESTASSERT(measid_item->meas_id == 2 and measid_item->meas_obj_id == 1 and measid_item->report_cfg_id == 2); - - // TEST 2: measConfig is empty if nothing was updated - src_var = target_var; - src_var.compute_diff_meas_cfg(target_var, &result_meascfg); - TESTASSERT(not result_meascfg.meas_obj_to_add_mod_list_present and not result_meascfg.meas_obj_to_rem_list_present); - TESTASSERT(result_meascfg.meas_obj_to_add_mod_list.size() == 0); - TESTASSERT(not result_meascfg.report_cfg_to_add_mod_list_present and - not result_meascfg.report_cfg_to_rem_list_present); - TESTASSERT(result_meascfg.report_cfg_to_add_mod_list.size() == 0); - - // TEST 3: Cell is added to cellsToAddModList if just a field was updated - cell1.q_offset = 5; - src_var = target_var; - target_var.add_cell_cfg(cell1); - src_var.compute_diff_meas_cfg(target_var, &result_meascfg); - TESTASSERT(result_meascfg.meas_obj_to_add_mod_list_present); - TESTASSERT(result_meascfg.meas_obj_to_add_mod_list.size() == 1); - item = &result_meascfg.meas_obj_to_add_mod_list[0]; - TESTASSERT(item->meas_obj_id == 1 and - item->meas_obj.type().value == meas_obj_to_add_mod_s::meas_obj_c_::types_opts::meas_obj_eutra); - eutra = item->meas_obj.meas_obj_eutra(); - TESTASSERT(eutra.cells_to_add_mod_list_present and not eutra.cells_to_rem_list_present); - TESTASSERT(eutra.cells_to_add_mod_list.size() == 1); - cell_item = &eutra.cells_to_add_mod_list[0]; - TESTASSERT(is_cell_cfg_equal(cell1, *cell_item)); - - // TEST 4: Removal of cell/rep from target propagates to the resulting meas_cfg_s - src_var = target_var; - TESTASSERT(src_var.meas_objs().size() == 1); - TESTASSERT(src_var.meas_objs()[0].meas_obj.meas_obj_eutra().cells_to_add_mod_list.size() == 2); - target_var = {}; - target_var.add_cell_cfg(cell2); - target_var.add_report_cfg(rep1); - target_var.add_report_cfg(rep3); - src_var.compute_diff_meas_cfg(target_var, &result_meascfg); - TESTASSERT(result_meascfg.meas_obj_to_add_mod_list_present); - TESTASSERT(result_meascfg.meas_obj_to_add_mod_list.size() == 1); - item = &result_meascfg.meas_obj_to_add_mod_list[0]; - TESTASSERT(item->meas_obj_id == 1 and - item->meas_obj.type().value == meas_obj_to_add_mod_s::meas_obj_c_::types_opts::meas_obj_eutra); - eutra = item->meas_obj.meas_obj_eutra(); - TESTASSERT(eutra.cells_to_add_mod_list_present and eutra.cells_to_add_mod_list.size() == 1); - TESTASSERT(eutra.cells_to_add_mod_list[0].pci == cell2.pci); - TESTASSERT(eutra.cells_to_rem_list_present and eutra.cells_to_rem_list.size() == 1); - TESTASSERT(eutra.cells_to_rem_list[0] == 2); - TESTASSERT(result_meascfg.report_cfg_to_add_mod_list_present and not result_meascfg.report_cfg_to_rem_list_present); - TESTASSERT(result_meascfg.report_cfg_to_add_mod_list.size() == 1); - TESTASSERT(result_meascfg.report_cfg_to_add_mod_list[0].report_cfg_id == 2); - TESTASSERT(result_meascfg.report_cfg_to_add_mod_list[0].report_cfg.report_cfg_eutra() == rep3); - } - - { - // TEST: creation of a var_meas_cfg using the srsenb::rrc_cfg_t - rrc_cfg_t cfg; - cfg.enb_id = 0x19B; - cfg.cell.nof_prb = 6; - cfg.meas_cfg_present = true; - cfg.cell_list.resize(2); - cfg.cell_list[0].dl_earfcn = 2850; - cfg.cell_list[0].cell_id = 0x01; - cfg.cell_list[0].scell_list.resize(1); - cfg.cell_list[0].scell_list[0].cell_id = 0x02; - cfg.cell_list[1].dl_earfcn = 3400; - cfg.cell_list[1].cell_id = 0x02; - cfg.sibs[1].set_sib2(); - - // TEST: correct construction of list of cells - cell_info_common_list cell_list{cfg}; - TESTASSERT(cell_list.nof_cells() == 2); - TESTASSERT(cell_list.get_cc_idx(0)->scells.size() == 1); - TESTASSERT(cell_list.get_cc_idx(0)->scells[0] == cell_list.get_cc_idx(1)); - TESTASSERT(cell_list.get_cc_idx(1)->scells.empty()); - - // measConfig only includes earfcns of active carriers for a given pcell - var_meas_cfg_t var_meas = var_meas_cfg_t::make(cfg, *cell_list.get_cc_idx(0)); - TESTASSERT(var_meas.meas_objs().size() == 2); - TESTASSERT(var_meas.meas_objs()[0].meas_obj.meas_obj_eutra().carrier_freq == 2850); - TESTASSERT(var_meas.meas_objs()[1].meas_obj.meas_obj_eutra().carrier_freq == 3400); - - var_meas_cfg_t var_meas2 = var_meas_cfg_t::make(cfg, *cell_list.get_cc_idx(1)); - TESTASSERT(var_meas2.meas_objs().size() == 1); - TESTASSERT(var_meas2.meas_objs()[0].meas_obj.meas_obj_eutra().carrier_freq == 3400); - } - - return SRSLTE_SUCCESS; -} - struct mobility_test_params { enum class test_event { success, @@ -378,8 +131,9 @@ struct s1ap_mobility_tester : public mobility_tester { int generate_rrc_cfg() final { TESTASSERT(generate_rrc_cfg_common() == SRSLTE_SUCCESS); - cfg.cell_list[0].meas_cfg.meas_cells[0].eci = 0x19C02; - cfg.cell_list[0].meas_cfg.meas_gap_period = 40; + cfg.cell_list[0].meas_cfg.meas_cells[0].eci = 0x19C02; + cfg.cell_list[0].meas_cfg.meas_cells[0].earfcn = 2850; + cfg.cell_list[0].meas_cfg.meas_gap_period = 40; return SRSLTE_SUCCESS; } }; @@ -389,15 +143,18 @@ struct intraenb_mobility_tester : public mobility_tester { int generate_rrc_cfg() final { TESTASSERT(generate_rrc_cfg_common() == SRSLTE_SUCCESS); - cfg.cell_list[0].meas_cfg.meas_cells[0].eci = 0x19B02; - cfg.cell_list[0].meas_cfg.meas_gap_period = 40; + cfg.cell_list[0].meas_cfg.meas_cells[0].eci = 0x19B02; + cfg.cell_list[0].meas_cfg.meas_gap_period = 40; + cfg.cell_list[0].meas_cfg.meas_cells[0].earfcn = 2850; - cell_cfg_t cell2 = cfg.cell_list[0]; - cell2.pci = 2; - cell2.cell_id = 2; - cell2.meas_cfg.meas_cells[0].pci = 1; - cell2.meas_cfg.meas_cells[0].eci = 0x19B01; - cell2.meas_cfg.meas_gap_period = 80; + cell_cfg_t cell2 = cfg.cell_list[0]; + cell2.pci = 2; + cell2.cell_id = 2; + cell2.dl_earfcn = 2850; + cell2.meas_cfg.meas_cells[0].pci = 1; + cell2.meas_cfg.meas_cells[0].earfcn = 3400; + cell2.meas_cfg.meas_cells[0].eci = 0x19B01; + cell2.meas_cfg.meas_gap_period = 80; cfg.cell_list.push_back(cell2); return SRSLTE_SUCCESS; @@ -747,8 +504,6 @@ int main(int argc, char** argv) return -1; } argparse::parse_args(argc, argv); - TESTASSERT(test_correct_insertion() == 0); - TESTASSERT(test_correct_meascfg_calculation() == 0); // S1AP Handover TESTASSERT(test_s1ap_mobility(mobility_test_params{event::wrong_measreport}) == 0); diff --git a/srsenb/test/upper/test_helpers.cc b/srsenb/test/upper/test_helpers.cc new file mode 100644 index 000000000..7104295da --- /dev/null +++ b/srsenb/test/upper/test_helpers.cc @@ -0,0 +1,164 @@ +/* + * Copyright 2013-2020 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 "test_helpers.h" +#include "srsenb/hdr/enb.h" +#include "srslte/common/test_common.h" + +namespace argparse { + +std::string repository_dir; +srslte::LOG_LEVEL_ENUM log_level; + +} // namespace argparse + +namespace test_helpers { + +int parse_default_cfg(rrc_cfg_t* rrc_cfg, srsenb::all_args_t& args) +{ + args = {}; + *rrc_cfg = {}; + args.enb_files.sib_config = argparse::repository_dir + "/sib.conf.example"; + args.enb_files.rr_config = argparse::repository_dir + "/rr.conf.example"; + args.enb_files.drb_config = argparse::repository_dir + "/drb.conf.example"; + srslte::logmap::get("TEST")->debug("sib file path=%s\n", args.enb_files.sib_config.c_str()); + + args.enb.enb_id = 0x19B; + args.enb.dl_earfcn = 3400; + args.enb.n_prb = 50; + TESTASSERT(srslte::string_to_mcc("001", &args.stack.s1ap.mcc)); + TESTASSERT(srslte::string_to_mnc("01", &args.stack.s1ap.mnc)); + args.enb.transmission_mode = 1; + args.enb.nof_ports = 1; + args.general.eia_pref_list = "EIA2, EIA1, EIA0"; + args.general.eea_pref_list = "EEA0, EEA2, EEA1"; + + args.general.rrc_inactivity_timer = 60000; + + phy_cfg_t phy_cfg; + + return enb_conf_sections::parse_cfg_files(&args, rrc_cfg, &phy_cfg); +} + +int bring_rrc_to_reconf_state(srsenb::rrc& rrc, srslte::timer_handler& timers, uint16_t rnti) +{ + srslte::unique_byte_buffer_t pdu; + + // Send RRCConnectionRequest + uint8_t rrc_conn_request[] = {0x40, 0x12, 0xf6, 0xfb, 0xe2, 0xc6}; + copy_msg_to_buffer(pdu, rrc_conn_request); + rrc.write_pdu(rnti, 0, std::move(pdu)); + timers.step_all(); + rrc.tti_clock(); + + // Send RRCConnectionSetupComplete + uint8_t rrc_conn_setup_complete[] = {0x20, 0x00, 0x40, 0x2e, 0x90, 0x50, 0x49, 0xe8, 0x06, 0x0e, 0x82, 0xa2, + 0x17, 0xec, 0x13, 0xe2, 0x0f, 0x00, 0x02, 0x02, 0x5e, 0xdf, 0x7c, 0x58, + 0x05, 0xc0, 0xc0, 0x00, 0x08, 0x04, 0x03, 0xa0, 0x23, 0x23, 0xc0}; + copy_msg_to_buffer(pdu, rrc_conn_setup_complete); + rrc.write_pdu(rnti, 1, std::move(pdu)); + timers.step_all(); + rrc.tti_clock(); + + // S1AP receives InitialContextSetupRequest and forwards it to RRC + uint8_t s1ap_init_ctxt_setup_req[] = { + 0x00, 0x09, 0x00, 0x80, 0xc6, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x42, 0x00, 0x0a, 0x18, 0x3b, 0x9a, 0xca, 0x00, 0x60, 0x3b, 0x9a, 0xca, 0x00, 0x00, 0x18, 0x00, 0x78, + 0x00, 0x00, 0x34, 0x00, 0x73, 0x45, 0x00, 0x09, 0x3c, 0x0f, 0x80, 0x0a, 0x00, 0x21, 0xf0, 0xb7, 0x36, 0x1c, 0x56, + 0x64, 0x27, 0x3e, 0x5b, 0x04, 0xb7, 0x02, 0x07, 0x42, 0x02, 0x3e, 0x06, 0x00, 0x09, 0xf1, 0x07, 0x00, 0x07, 0x00, + 0x37, 0x52, 0x66, 0xc1, 0x01, 0x09, 0x1b, 0x07, 0x74, 0x65, 0x73, 0x74, 0x31, 0x32, 0x33, 0x06, 0x6d, 0x6e, 0x63, + 0x30, 0x37, 0x30, 0x06, 0x6d, 0x63, 0x63, 0x39, 0x30, 0x31, 0x04, 0x67, 0x70, 0x72, 0x73, 0x05, 0x01, 0xc0, 0xa8, + 0x03, 0x02, 0x27, 0x0e, 0x80, 0x80, 0x21, 0x0a, 0x03, 0x00, 0x00, 0x0a, 0x81, 0x06, 0x08, 0x08, 0x08, 0x08, 0x50, + 0x0b, 0xf6, 0x09, 0xf1, 0x07, 0x80, 0x01, 0x01, 0xf6, 0x7e, 0x72, 0x69, 0x13, 0x09, 0xf1, 0x07, 0x00, 0x01, 0x23, + 0x05, 0xf4, 0xf6, 0x7e, 0x72, 0x69, 0x00, 0x6b, 0x00, 0x05, 0x18, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x20, + 0x45, 0x25, 0xe4, 0x9a, 0x77, 0xc8, 0xd5, 0xcf, 0x26, 0x33, 0x63, 0xeb, 0x5b, 0xb9, 0xc3, 0x43, 0x9b, 0x9e, 0xb3, + 0x86, 0x1f, 0xa8, 0xa7, 0xcf, 0x43, 0x54, 0x07, 0xae, 0x42, 0x2b, 0x63, 0xb9}; + asn1::s1ap::s1ap_pdu_c s1ap_pdu; + srslte::byte_buffer_t byte_buf; + byte_buf.N_bytes = sizeof(s1ap_init_ctxt_setup_req); + memcpy(byte_buf.msg, s1ap_init_ctxt_setup_req, byte_buf.N_bytes); + asn1::cbit_ref bref(byte_buf.msg, byte_buf.N_bytes); + TESTASSERT(s1ap_pdu.unpack(bref) == asn1::SRSASN_SUCCESS); + rrc.setup_ue_ctxt(rnti, s1ap_pdu.init_msg().value.init_context_setup_request()); + timers.step_all(); + rrc.tti_clock(); + + // Send SecurityModeComplete + uint8_t sec_mode_complete[] = {0x28, 0x00}; + copy_msg_to_buffer(pdu, sec_mode_complete); + rrc.write_pdu(rnti, 1, std::move(pdu)); + timers.step_all(); + rrc.tti_clock(); + + // send UE cap info + uint8_t ue_cap_info[] = {0x38, 0x01, 0x01, 0x0c, 0x98, 0x00, 0x00, 0x18, 0x00, 0x0f, + 0x30, 0x20, 0x80, 0x00, 0x01, 0x00, 0x0e, 0x01, 0x00, 0x00}; + copy_msg_to_buffer(pdu, ue_cap_info); + rrc.write_pdu(rnti, 1, std::move(pdu)); + timers.step_all(); + rrc.tti_clock(); + + // RRCConnectionReconfiguration was sent. Send RRCConnectionReconfigurationComplete + uint8_t rrc_conn_reconf_complete[] = {0x10, 0x00}; + copy_msg_to_buffer(pdu, rrc_conn_reconf_complete); + rrc.write_pdu(rnti, 1, std::move(pdu)); + timers.step_all(); + rrc.tti_clock(); + + return SRSLTE_SUCCESS; +} + +} // namespace test_helpers + +namespace srsenb { + +meas_cell_cfg_t generate_cell1() +{ + meas_cell_cfg_t cell1{}; + cell1.earfcn = 3400; + cell1.pci = 1; + cell1.q_offset = 0; + cell1.eci = 0x19C01; + return cell1; +} + +report_cfg_eutra_s generate_rep1() +{ + report_cfg_eutra_s rep{}; + rep.report_amount.value = report_cfg_eutra_s::report_amount_opts::r16; + rep.report_interv.value = report_interv_opts::ms240; + rep.max_report_cells = 2; + rep.report_quant.value = report_cfg_eutra_s::report_quant_opts::both; + rep.trigger_quant.value = report_cfg_eutra_s::trigger_quant_opts::rsrp; + rep.trigger_type.set_event().event_id.set_event_a3(); + rep.trigger_type.event().time_to_trigger.value = time_to_trigger_opts::ms100; + rep.trigger_type.event().hysteresis = 0; + rep.trigger_type.event().event_id.event_a3().a3_offset = 5; + rep.trigger_type.event().event_id.event_a3().report_on_leave = true; + return rep; +} + +bool is_cell_cfg_equal(const meas_cell_cfg_t& cfg, const cells_to_add_mod_s& cell) +{ + return cfg.pci == cell.pci and cell.cell_individual_offset.to_number() == (int8_t)round(cfg.q_offset); +} + +} // namespace srsenb \ No newline at end of file diff --git a/srsenb/test/upper/test_helpers.h b/srsenb/test/upper/test_helpers.h index f6937fcec..7b1636151 100644 --- a/srsenb/test/upper/test_helpers.h +++ b/srsenb/test/upper/test_helpers.h @@ -22,26 +22,26 @@ #ifndef SRSENB_TEST_HELPERS_H #define SRSENB_TEST_HELPERS_H +#include "srsenb/src/enb_cfg_parser.h" #include "srsenb/test/common/dummy_classes.h" #include "srslte/adt/span.h" #include "srslte/common/log_filter.h" -#include "srsenb/src/enb_cfg_parser.h" using namespace srsenb; using namespace asn1::rrc; namespace argparse { -std::string repository_dir; -srslte::LOG_LEVEL_ENUM log_level; +extern std::string repository_dir; +extern srslte::LOG_LEVEL_ENUM log_level; -void usage(char* prog) +inline void usage(char* prog) { printf("Usage: %s [v] -i repository_dir\n", prog); printf("\t-v [set srslte_verbose to debug, default none]\n"); } -void parse_args(int argc, char** argv) +inline void parse_args(int argc, char** argv) { int opt; @@ -217,31 +217,7 @@ public: namespace test_helpers { -int parse_default_cfg(rrc_cfg_t* rrc_cfg, srsenb::all_args_t& args) -{ - args = {}; - *rrc_cfg = {}; - args.enb_files.sib_config = argparse::repository_dir + "/sib.conf.example"; - args.enb_files.rr_config = argparse::repository_dir + "/rr.conf.example"; - args.enb_files.drb_config = argparse::repository_dir + "/drb.conf.example"; - srslte::logmap::get("TEST")->debug("sib file path=%s\n", args.enb_files.sib_config.c_str()); - - args.enb.enb_id = 0x19B; - args.enb.dl_earfcn = 3400; - args.enb.n_prb = 50; - TESTASSERT(srslte::string_to_mcc("001", &args.stack.s1ap.mcc)); - TESTASSERT(srslte::string_to_mnc("01", &args.stack.s1ap.mnc)); - args.enb.transmission_mode = 1; - args.enb.nof_ports = 1; - args.general.eia_pref_list = "EIA2, EIA1, EIA0"; - args.general.eea_pref_list = "EEA0, EEA2, EEA1"; - - args.general.rrc_inactivity_timer = 60000; - - phy_cfg_t phy_cfg; - - return enb_conf_sections::parse_cfg_files(&args, rrc_cfg, &phy_cfg); -} +int parse_default_cfg(rrc_cfg_t* rrc_cfg, srsenb::all_args_t& args); template bool unpack_asn1(ASN1Type& asn1obj, srslte::const_byte_span pdu) @@ -254,7 +230,7 @@ bool unpack_asn1(ASN1Type& asn1obj, srslte::const_byte_span pdu) return true; } -void copy_msg_to_buffer(srslte::unique_byte_buffer_t& pdu, srslte::const_byte_span msg) +inline void copy_msg_to_buffer(srslte::unique_byte_buffer_t& pdu, srslte::const_byte_span msg) { srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance(); pdu = srslte::allocate_unique_buffer(*pool, true); @@ -262,74 +238,18 @@ void copy_msg_to_buffer(srslte::unique_byte_buffer_t& pdu, srslte::const_byte_sp pdu->N_bytes = msg.size(); } -int bring_rrc_to_reconf_state(srsenb::rrc& rrc, srslte::timer_handler& timers, uint16_t rnti) -{ - srslte::unique_byte_buffer_t pdu; - - // Send RRCConnectionRequest - uint8_t rrc_conn_request[] = {0x40, 0x12, 0xf6, 0xfb, 0xe2, 0xc6}; - copy_msg_to_buffer(pdu, rrc_conn_request); - rrc.write_pdu(rnti, 0, std::move(pdu)); - timers.step_all(); - rrc.tti_clock(); - - // Send RRCConnectionSetupComplete - uint8_t rrc_conn_setup_complete[] = {0x20, 0x00, 0x40, 0x2e, 0x90, 0x50, 0x49, 0xe8, 0x06, 0x0e, 0x82, 0xa2, - 0x17, 0xec, 0x13, 0xe2, 0x0f, 0x00, 0x02, 0x02, 0x5e, 0xdf, 0x7c, 0x58, - 0x05, 0xc0, 0xc0, 0x00, 0x08, 0x04, 0x03, 0xa0, 0x23, 0x23, 0xc0}; - copy_msg_to_buffer(pdu, rrc_conn_setup_complete); - rrc.write_pdu(rnti, 1, std::move(pdu)); - timers.step_all(); - rrc.tti_clock(); - - // S1AP receives InitialContextSetupRequest and forwards it to RRC - uint8_t s1ap_init_ctxt_setup_req[] = { - 0x00, 0x09, 0x00, 0x80, 0xc6, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x00, 0x08, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x42, 0x00, 0x0a, 0x18, 0x3b, 0x9a, 0xca, 0x00, 0x60, 0x3b, 0x9a, 0xca, 0x00, 0x00, 0x18, 0x00, 0x78, - 0x00, 0x00, 0x34, 0x00, 0x73, 0x45, 0x00, 0x09, 0x3c, 0x0f, 0x80, 0x0a, 0x00, 0x21, 0xf0, 0xb7, 0x36, 0x1c, 0x56, - 0x64, 0x27, 0x3e, 0x5b, 0x04, 0xb7, 0x02, 0x07, 0x42, 0x02, 0x3e, 0x06, 0x00, 0x09, 0xf1, 0x07, 0x00, 0x07, 0x00, - 0x37, 0x52, 0x66, 0xc1, 0x01, 0x09, 0x1b, 0x07, 0x74, 0x65, 0x73, 0x74, 0x31, 0x32, 0x33, 0x06, 0x6d, 0x6e, 0x63, - 0x30, 0x37, 0x30, 0x06, 0x6d, 0x63, 0x63, 0x39, 0x30, 0x31, 0x04, 0x67, 0x70, 0x72, 0x73, 0x05, 0x01, 0xc0, 0xa8, - 0x03, 0x02, 0x27, 0x0e, 0x80, 0x80, 0x21, 0x0a, 0x03, 0x00, 0x00, 0x0a, 0x81, 0x06, 0x08, 0x08, 0x08, 0x08, 0x50, - 0x0b, 0xf6, 0x09, 0xf1, 0x07, 0x80, 0x01, 0x01, 0xf6, 0x7e, 0x72, 0x69, 0x13, 0x09, 0xf1, 0x07, 0x00, 0x01, 0x23, - 0x05, 0xf4, 0xf6, 0x7e, 0x72, 0x69, 0x00, 0x6b, 0x00, 0x05, 0x18, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x20, - 0x45, 0x25, 0xe4, 0x9a, 0x77, 0xc8, 0xd5, 0xcf, 0x26, 0x33, 0x63, 0xeb, 0x5b, 0xb9, 0xc3, 0x43, 0x9b, 0x9e, 0xb3, - 0x86, 0x1f, 0xa8, 0xa7, 0xcf, 0x43, 0x54, 0x07, 0xae, 0x42, 0x2b, 0x63, 0xb9}; - asn1::s1ap::s1ap_pdu_c s1ap_pdu; - srslte::byte_buffer_t byte_buf; - byte_buf.N_bytes = sizeof(s1ap_init_ctxt_setup_req); - memcpy(byte_buf.msg, s1ap_init_ctxt_setup_req, byte_buf.N_bytes); - asn1::cbit_ref bref(byte_buf.msg, byte_buf.N_bytes); - TESTASSERT(s1ap_pdu.unpack(bref) == asn1::SRSASN_SUCCESS); - rrc.setup_ue_ctxt(rnti, s1ap_pdu.init_msg().value.init_context_setup_request()); - timers.step_all(); - rrc.tti_clock(); - - // Send SecurityModeComplete - uint8_t sec_mode_complete[] = {0x28, 0x00}; - copy_msg_to_buffer(pdu, sec_mode_complete); - rrc.write_pdu(rnti, 1, std::move(pdu)); - timers.step_all(); - rrc.tti_clock(); - - // send UE cap info - uint8_t ue_cap_info[] = {0x38, 0x01, 0x01, 0x0c, 0x98, 0x00, 0x00, 0x18, 0x00, 0x0f, - 0x30, 0x20, 0x80, 0x00, 0x01, 0x00, 0x0e, 0x01, 0x00, 0x00}; - copy_msg_to_buffer(pdu, ue_cap_info); - rrc.write_pdu(rnti, 1, std::move(pdu)); - timers.step_all(); - rrc.tti_clock(); - - // RRCConnectionReconfiguration was sent. Send RRCConnectionReconfigurationComplete - uint8_t rrc_conn_reconf_complete[] = {0x10, 0x00}; - copy_msg_to_buffer(pdu, rrc_conn_reconf_complete); - rrc.write_pdu(rnti, 1, std::move(pdu)); - timers.step_all(); - rrc.tti_clock(); - - return SRSLTE_SUCCESS; -} +int bring_rrc_to_reconf_state(srsenb::rrc& rrc, srslte::timer_handler& timers, uint16_t rnti); } // namespace test_helpers +namespace srsenb { + +meas_cell_cfg_t generate_cell1(); + +report_cfg_eutra_s generate_rep1(); + +bool is_cell_cfg_equal(const meas_cell_cfg_t& cfg, const cells_to_add_mod_s& cell); + +} // namespace srsenb + #endif // SRSENB_TEST_HELPERS_H