move rrc measconfig handling functions to separate file. Update measconfig tests

master
Francisco 4 years ago committed by Andre Puschmann
parent 1cb65f07f1
commit 25bfb6d84d

@ -113,6 +113,7 @@ struct cell_ctxt_dedicated {
cell_ctxt_dedicated& operator=(cell_ctxt_dedicated&&) noexcept = default; 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_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 */ /** Class used to handle the allocation of a UE's resources across its cells */
@ -137,12 +138,16 @@ public:
return (ue_cc_idx < nof_cells()) ? &cell_ded_list[ue_cc_idx] : nullptr; 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); 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(); } size_t nof_cells() const { return cell_ded_list.size(); }
bool is_allocated() const { return nof_cells() > 0; } bool is_allocated() const { return nof_cells() > 0; }
using iterator = std::vector<cell_ctxt_dedicated>::iterator; using iterator = std::vector<cell_ctxt_dedicated>::iterator;
using const_iterator = std::vector<cell_ctxt_dedicated>::const_iterator;
iterator begin() { return cell_ded_list.begin(); } iterator begin() { return cell_ded_list.begin(); }
iterator end() { return cell_ded_list.end(); } 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 { struct sr_res_t {
int sr_sched_sf_idx = 0; int sr_sched_sf_idx = 0;

@ -74,7 +74,7 @@ constexpr uint32_t UE_PCELL_CC_IDX = 0;
struct ue_var_cfg_t { struct ue_var_cfg_t {
asn1::rrc::rr_cfg_ded_s rr_cfg; 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; asn1::rrc::scell_to_add_mod_list_r10_l scells;
}; };

@ -115,7 +115,8 @@ private:
// Handover to target cell // Handover to target cell
void fill_mobility_reconf_common(asn1::rrc::dl_dcch_msg_s& msg, void fill_mobility_reconf_common(asn1::rrc::dl_dcch_msg_s& msg,
const cell_info_common& target_cell, 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); 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; rrc::ue* rrc_ue = nullptr;
@ -124,7 +125,7 @@ private:
srslte::log_ref rrc_log; srslte::log_ref rrc_log;
// vars // 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; asn1::rrc::rrc_conn_recfg_complete_s pending_recfg_complete;
// events // events

@ -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<bool, meas_obj_t*> add_meas_obj(meas_obj_list& list, uint32_t dl_earfcn);
std::tuple<bool, meas_obj_t*, meas_cell_t*> 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<meas_obj_t*, meas_cell_t*> 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

@ -18,7 +18,7 @@
# and at http://www.gnu.org/licenses/. # 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}) add_library(srsenb_rrc STATIC ${SOURCES})
if (ENABLE_5GNR) if (ENABLE_5GNR)

@ -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); 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) 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); const cell_info_common* cell_common = common_list.get_cc_idx(enb_cc_idx);

@ -22,6 +22,7 @@
#include "srsenb/hdr/stack/rrc/rrc_mobility.h" #include "srsenb/hdr/stack/rrc/rrc_mobility.h"
#include "srsenb/hdr/stack/rrc/mac_controller.h" #include "srsenb/hdr/stack/rrc/mac_controller.h"
#include "srsenb/hdr/stack/rrc/rrc_cell_cfg.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 "srsenb/hdr/stack/rrc/ue_rr_cfg.h"
#include "srslte/asn1/rrc_utils.h" #include "srslte/asn1/rrc_utils.h"
#include "srslte/common/bcd_helpers.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 // 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); conn_recfg->meas_cfg_present = apply_meascfg_updates(
uint32_t src_earfcn = pcell->get_dl_earfcn(); conn_recfg->meas_cfg, rrc_ue->current_ue_cfg.meas_cfg, rrc_ue->cell_ded_list);
conn_recfg->meas_cfg_present = update_ue_var_meas_cfg(src_earfcn, *pcell->cell_common, &conn_recfg->meas_cfg);
return conn_recfg->meas_cfg_present; 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"); Error("MeasReports regarding non-EUTRA are not supported!\n");
return; return;
} }
auto measid_it = srslte::find_rrc_obj_id(ue_var_meas.meas_ids(), meas_res.meas_id); const meas_id_list& measid_list = rrc_ue->current_ue_cfg.meas_cfg.meas_id_to_add_mod_list;
if (measid_it == ue_var_meas.meas_ids().end()) { 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); Warning("The measurement ID %d provided by the UE does not exist.\n", meas_res.meas_id);
return; return;
} }
@ -614,7 +616,7 @@ void rrc::ue::rrc_mobility::handle_ue_meas_report(const meas_report_s& msg)
// Find respective ReportCfg and MeasObj // Find respective ReportCfg and MeasObj
ho_meas_report_ev meas_ev{}; 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); meas_ev.meas_obj = &(*obj_it);
// iterate from strongest to weakest cell // 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_present = true;
hoprep_r8.as_cfg.source_rr_cfg = rrc_ue->current_ue_cfg.rr_cfg; 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}); 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 hoprep_r8.as_cfg.source_meas_cfg = rrc_ue->current_ue_cfg.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);
// Get security 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_security_algorithm_cfg = rrc_ue->ue_security_cfg.get_security_algorithm_cfg();
hoprep_r8.as_cfg.source_ue_id.from_number(rrc_ue->rnti); 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<s1_target_ho_st>(); return is_in_state<s1_target_ho_st>();
} }
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 * @brief Fills RRCConnectionReconfigurationMessage with Handover Command fields that are common to
* all types of handover (e.g. S1, intra-enb, X2), namely: * 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, void rrc::ue::rrc_mobility::fill_mobility_reconf_common(asn1::rrc::dl_dcch_msg_s& msg,
const cell_info_common& target_cell, 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(); auto& recfg = msg.msg.set_c1().set_rrc_conn_recfg();
recfg.rrc_transaction_id = rrc_ue->transaction_id; 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(); intralte.next_hop_chaining_count = rrc_ue->ue_security_cfg.get_ncc();
// Add MeasConfig of target cell // 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, apply_reconf_updates(recfg_r8,
rrc_ue->current_ue_cfg, 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); 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 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(); 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 // 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 // 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); 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 // Save source UE MAC configuration as a base
rrc_ue->mac_ctrl->handle_ho_prep(ho_prep); 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; 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 */ /* Prepare RRC Reconf Message with mobility info */
dl_dcch_msg_s dl_dcch_msg; 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(); 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 // Apply changes to the MAC scheduler

@ -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.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(); 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 // Fill RR Config Ded and SCells
apply_reconf_updates(recfg_r8, apply_reconf_updates(recfg_r8,
current_ue_cfg, current_ue_cfg,
@ -490,6 +485,11 @@ void rrc::ue::send_connection_reconf(srslte::unique_byte_buffer_t pdu, bool phy_
ue_capabilities, ue_capabilities,
phy_cfg_updated); 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 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 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)) { recfg_r8.ded_info_nas_list_present or recfg_r8.security_cfg_ho_present or recfg_r8.non_crit_ext_present)) {

@ -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<meas_obj_t*, cells_to_add_mod_s*> 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<bool, meas_obj_t*> 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<bool, meas_obj_t*, cells_to_add_mod_s*> 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<meas_obj_t*, meas_cell_t*> 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<uint32_t>(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 ? &current_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

@ -38,8 +38,6 @@ using namespace asn1::rrc;
namespace srsenb { namespace srsenb {
srslte::log_ref log_h = srslte::logmap::get("RRC");
/****************************** /******************************
* SRBs / DRBs * 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) 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) { 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; return nullptr;
} }
@ -116,7 +114,7 @@ int16_t get_ri(uint32_t m_ri)
ri_idx = 805 - N_offset_ri; ri_idx = 805 - N_offset_ri;
break; break;
default: 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; return -1;
} }
@ -148,7 +146,7 @@ int fill_cqi_report_setup(cqi_report_cfg_s& cqi_rep,
if (cqi_rep.cqi_report_periodic_present) { if (cqi_rep.cqi_report_periodic_present) {
const cell_ctxt_dedicated* pcell = ue_cell_list.get_ue_cc_idx(UE_PCELL_CC_IDX); 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) { 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; return SRSLTE_ERROR;
} }
auto& cqi_periodic = cqi_rep.cqi_report_periodic.setup(); 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_present = true;
cqi_setup.ri_cfg_idx = ri_idx; cqi_setup.ri_cfg_idx = ri_idx;
} else { } 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, * measConfig
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;
}
/// Apply Reconf updates and update current state /// Apply Reconf updates and update current state
void apply_reconf_updates(asn1::rrc::rrc_conn_recfg_r8_ies_s& recfg_r8, 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( 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); 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); 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; recfg_r8.meas_cfg_present |= recfg_r8.meas_cfg.meas_gap_cfg_present;
// Add pending NAS info // Add pending NAS info

@ -18,15 +18,22 @@
# and at http://www.gnu.org/licenses/. # 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 # Simple PLMN -> MCC/MNC test
add_executable(plmn_test plmn_test.cc) add_executable(plmn_test plmn_test.cc)
target_link_libraries(plmn_test rrc_asn1) target_link_libraries(plmn_test rrc_asn1)
add_executable(rrc_mobility_test rrc_mobility_test.cc) 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) 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(rrc_mobility_test rrc_mobility_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..)
add_test(erab_setup_test erab_setup_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..) add_test(erab_setup_test erab_setup_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..)

@ -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;
}

@ -30,253 +30,6 @@
using namespace asn1::rrc; 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 { struct mobility_test_params {
enum class test_event { enum class test_event {
success, success,
@ -379,6 +132,7 @@ struct s1ap_mobility_tester : public mobility_tester {
{ {
TESTASSERT(generate_rrc_cfg_common() == SRSLTE_SUCCESS); 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_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; cfg.cell_list[0].meas_cfg.meas_gap_period = 40;
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -391,11 +145,14 @@ struct intraenb_mobility_tester : public mobility_tester {
TESTASSERT(generate_rrc_cfg_common() == SRSLTE_SUCCESS); 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_cells[0].eci = 0x19B02;
cfg.cell_list[0].meas_cfg.meas_gap_period = 40; 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]; cell_cfg_t cell2 = cfg.cell_list[0];
cell2.pci = 2; cell2.pci = 2;
cell2.cell_id = 2; cell2.cell_id = 2;
cell2.dl_earfcn = 2850;
cell2.meas_cfg.meas_cells[0].pci = 1; 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_cells[0].eci = 0x19B01;
cell2.meas_cfg.meas_gap_period = 80; cell2.meas_cfg.meas_gap_period = 80;
cfg.cell_list.push_back(cell2); cfg.cell_list.push_back(cell2);
@ -747,8 +504,6 @@ int main(int argc, char** argv)
return -1; return -1;
} }
argparse::parse_args(argc, argv); argparse::parse_args(argc, argv);
TESTASSERT(test_correct_insertion() == 0);
TESTASSERT(test_correct_meascfg_calculation() == 0);
// S1AP Handover // S1AP Handover
TESTASSERT(test_s1ap_mobility(mobility_test_params{event::wrong_measreport}) == 0); TESTASSERT(test_s1ap_mobility(mobility_test_params{event::wrong_measreport}) == 0);

@ -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

@ -22,26 +22,26 @@
#ifndef SRSENB_TEST_HELPERS_H #ifndef SRSENB_TEST_HELPERS_H
#define SRSENB_TEST_HELPERS_H #define SRSENB_TEST_HELPERS_H
#include "srsenb/src/enb_cfg_parser.h"
#include "srsenb/test/common/dummy_classes.h" #include "srsenb/test/common/dummy_classes.h"
#include "srslte/adt/span.h" #include "srslte/adt/span.h"
#include "srslte/common/log_filter.h" #include "srslte/common/log_filter.h"
#include "srsenb/src/enb_cfg_parser.h"
using namespace srsenb; using namespace srsenb;
using namespace asn1::rrc; using namespace asn1::rrc;
namespace argparse { namespace argparse {
std::string repository_dir; extern std::string repository_dir;
srslte::LOG_LEVEL_ENUM log_level; 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("Usage: %s [v] -i repository_dir\n", prog);
printf("\t-v [set srslte_verbose to debug, default none]\n"); 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; int opt;
@ -217,31 +217,7 @@ public:
namespace test_helpers { namespace test_helpers {
int parse_default_cfg(rrc_cfg_t* rrc_cfg, srsenb::all_args_t& args) 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);
}
template <typename ASN1Type> template <typename ASN1Type>
bool unpack_asn1(ASN1Type& asn1obj, srslte::const_byte_span pdu) 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; 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(); srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance();
pdu = srslte::allocate_unique_buffer(*pool, true); 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(); pdu->N_bytes = msg.size();
} }
int bring_rrc_to_reconf_state(srsenb::rrc& rrc, srslte::timer_handler& timers, uint16_t rnti) 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 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 #endif // SRSENB_TEST_HELPERS_H

Loading…
Cancel
Save