updated rrc mobility parsing. added some utility methods

This commit is contained in:
Francisco Paisana 2020-04-21 12:18:08 +01:00 committed by Francisco Paisana
parent 20f6655c6b
commit 0526ae8ab1
13 changed files with 267 additions and 120 deletions

View File

@ -484,6 +484,25 @@ private:
std::list<proc_obj_t> proc_list;
};
template <typename Functor>
struct deferred_callback {
explicit deferred_callback(Functor&& f_) : f(std::forward<Functor>(f_)) {}
deferred_callback(const deferred_callback&) = delete;
deferred_callback(deferred_callback&&) noexcept = default;
deferred_callback& operator=(const deferred_callback&) = delete;
deferred_callback& operator=(deferred_callback&&) noexcept = default;
~deferred_callback() { f(); }
private:
Functor f;
};
template <typename Functor>
deferred_callback<Functor> defer_call(Functor&& f)
{
return deferred_callback<Functor>{std::forward<Functor>(f)};
}
#define DEFER(FUNC) auto on_exit_call = ::srslte::defer_call([&]() { FUNC })
} // namespace srslte
#endif // SRSLTE_RESUMABLE_PROCEDURES_H

View File

@ -390,30 +390,6 @@ public:
virtual uint8_t* read_pdu_bcch_dlsch(const uint8_t enb_cc_idx, const uint32_t sib_index) = 0;
};
// SCell configuration
struct scell_cfg_t {
uint32_t cell_id;
bool cross_carrier_sched = false;
uint32_t sched_cell_id;
bool ul_allowed;
};
// Cell/Sector configuration
struct cell_cfg_t {
uint32_t rf_port;
uint32_t cell_id;
uint16_t tac;
uint32_t pci;
uint16_t root_seq_idx;
uint32_t dl_earfcn;
double dl_freq_hz;
uint32_t ul_earfcn;
double ul_freq_hz;
uint32_t initial_dl_cqi;
std::vector<scell_cfg_t> scell_list;
};
typedef std::vector<cell_cfg_t> cell_list_t;
// RRC interface for PDCP
class rrc_interface_pdcp
{

View File

@ -0,0 +1,74 @@
/*
* 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_ENB_RRC_INTERFACE_TYPES_H
#define SRSLTE_ENB_RRC_INTERFACE_TYPES_H
#include <vector>
namespace srsenb {
// SCell configuration
struct scell_cfg_t {
uint32_t cell_id;
bool cross_carrier_sched = false;
uint32_t sched_cell_id;
bool ul_allowed;
};
// Cell to measure for Handover
struct meas_cell_cfg_t {
uint32_t earfcn;
uint16_t pci;
uint32_t eci;
float q_offset;
};
// neigh measurement Cell info
struct rrc_meas_cfg_t {
std::vector<meas_cell_cfg_t> meas_cells;
std::vector<asn1::rrc::report_cfg_eutra_s> meas_reports;
asn1::rrc::quant_cfg_eutra_s quant_cfg;
// TODO: Add blacklist cells
// TODO: Add multiple meas configs
};
// Cell/Sector configuration
struct cell_cfg_t {
uint32_t rf_port;
uint32_t cell_id;
uint16_t tac;
uint32_t pci;
uint16_t root_seq_idx;
uint32_t dl_earfcn;
double dl_freq_hz;
uint32_t ul_earfcn;
double ul_freq_hz;
uint32_t initial_dl_cqi;
std::vector<scell_cfg_t> scell_list;
rrc_meas_cfg_t meas_cfg;
};
typedef std::vector<cell_cfg_t> cell_list_t;
} // namespace srsenb
#endif // SRSLTE_ENB_RRC_INTERFACE_TYPES_H

View File

@ -38,6 +38,7 @@
#include "srsenb/hdr/enb.h"
#include "srslte/common/multiqueue.h"
#include "srslte/interfaces/enb_interfaces.h"
#include "srslte/interfaces/enb_rrc_interface_types.h"
namespace srsenb {

View File

@ -30,6 +30,7 @@
#include "srslte/common/tti_sync_cv.h"
#include "srslte/interfaces/enb_interfaces.h"
#include "srslte/interfaces/enb_metrics_interface.h"
#include "srslte/interfaces/enb_rrc_interface_types.h"
#include "srslte/interfaces/sched_interface.h"
#include "ta.h"
#include "ue.h"

View File

@ -32,6 +32,7 @@
#include "srslte/common/stack_procedure.h"
#include "srslte/common/timeout.h"
#include "srslte/interfaces/enb_interfaces.h"
#include "srslte/interfaces/enb_rrc_interface_types.h"
#include <map>
#include <queue>
@ -66,25 +67,6 @@ typedef struct {
asn1::rrc::rlc_cfg_c rlc_cfg;
} rrc_cfg_qci_t;
//! Cell to measure for HO. Filled by cfg file parser.
struct meas_cell_cfg_t {
uint32_t earfcn;
uint16_t pci;
uint32_t eci;
float q_offset;
};
// neigh measurement Cell info
struct rrc_meas_cfg_t {
std::vector<meas_cell_cfg_t> meas_cells;
std::vector<asn1::rrc::report_cfg_eutra_s> meas_reports;
asn1::rrc::quant_cfg_eutra_s quant_cfg;
// uint32_t nof_meas_ids;
// srslte::rrc_meas_id_t meas_ids[LIBLTE_RRC_MAX_MEAS_ID];
// TODO: Add blacklist cells
// TODO: Add multiple meas configs
};
#define MAX_NOF_QCI 10
struct rrc_cfg_t {
@ -105,7 +87,6 @@ struct rrc_cfg_t {
srslte::CIPHERING_ALGORITHM_ID_ENUM eea_preference_list[srslte::CIPHERING_ALGORITHM_ID_N_ITEMS];
srslte::INTEGRITY_ALGORITHM_ID_ENUM eia_preference_list[srslte::INTEGRITY_ALGORITHM_ID_N_ITEMS];
bool meas_cfg_present = false;
rrc_meas_cfg_t meas_cfg;
srslte_cell_t cell;
cell_list_t cell_list;
};
@ -269,7 +250,8 @@ private:
uint16_t rnti = 0;
rrc* parent = nullptr;
bool connect_notified = false;
bool connect_notified = false;
std::unique_ptr<rrc_mobility> mobility_handler;
bool is_csfb = false;
@ -283,7 +265,6 @@ private:
asn1::rrc::security_algorithm_cfg_s last_security_mode_cmd;
asn1::rrc::establishment_cause_e establishment_cause;
std::unique_ptr<rrc_mobility> mobility_handler;
// S-TMSI for this UE
bool has_tmsi = false;
@ -436,8 +417,8 @@ private:
uint32_t nof_si_messages = 0;
asn1::rrc::sib_type7_s sib7;
class mobility_cfg;
std::unique_ptr<mobility_cfg> enb_mobility_cfg;
class enb_mobility_handler;
std::unique_ptr<enb_mobility_handler> enb_mobility_cfg;
void rem_user_thread(uint16_t rnti);

View File

@ -63,21 +63,26 @@ public:
asn1::rrc::report_cfg_to_add_mod_list_l& rep_cfgs() { return var_meas.report_cfg_list; }
asn1::rrc::meas_id_to_add_mod_list_l& meas_ids() { return var_meas.meas_id_list; }
static var_meas_cfg_t make(const asn1::rrc::meas_cfg_s& meas_cfg);
private:
asn1::rrc::var_meas_cfg_s var_meas;
srslte::log_ref rrc_log;
};
class rrc::mobility_cfg
class rrc::enb_mobility_handler
{
public:
explicit mobility_cfg(const rrc_cfg_t* cfg_);
explicit enb_mobility_handler(rrc* rrc_);
std::shared_ptr<const var_meas_cfg_t> current_meas_cfg; ///< const to enable ptr comparison as identity comparison
//! Variable used to store the MeasConfig expected for each cell.
// Note: Made const to forbid silent updates and enable comparison based on addr
std::vector<std::shared_ptr<const var_meas_cfg_t> > cell_meas_cfg_list;
private:
// args
const rrc_cfg_t* cfg = nullptr;
rrc* rrc_ptr = nullptr;
const rrc_cfg_t* cfg = nullptr;
};
class rrc::ue::rrc_mobility
@ -94,11 +99,18 @@ private:
bool start_ho_preparation(uint32_t target_eci, uint8_t measobj_id, bool fwd_direct_path_available);
bool start_enb_status_transfer();
rrc::ue* rrc_ue = nullptr;
rrc* rrc_enb = nullptr;
rrc::mobility_cfg* cfg = nullptr;
srslte::byte_buffer_pool* pool = nullptr;
srslte::log_ref rrc_log;
bool update_ue_var_meas_cfg(const asn1::rrc::meas_cfg_s& source_meas_cfg,
uint32_t target_enb_cc_idx,
asn1::rrc::meas_cfg_s* diff_meas_cfg);
bool update_ue_var_meas_cfg(const var_meas_cfg_t& source_var_meas_cfg,
uint32_t target_enb_cc_idx,
asn1::rrc::meas_cfg_s* diff_meas_cfg);
rrc::ue* rrc_ue = nullptr;
rrc* rrc_enb = nullptr;
rrc::enb_mobility_handler* cfg = nullptr;
srslte::byte_buffer_pool* pool = nullptr;
srslte::log_ref rrc_log;
// vars
std::shared_ptr<const var_meas_cfg_t> ue_var_meas;

View File

@ -720,8 +720,8 @@ static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root)
parse_default_field(cell_cfg.initial_dl_cqi, cellroot, "initial_dl_cqi", 5u);
if (cellroot["ho_active"]) {
HANDLEPARSERCODE(parse_meas_cell_list(&rrc_cfg->meas_cfg, cellroot["meas_cell_list"]));
HANDLEPARSERCODE(parse_meas_report_desc(&rrc_cfg->meas_cfg, cellroot["meas_report_desc"]));
HANDLEPARSERCODE(parse_meas_cell_list(&cell_cfg.meas_cfg, cellroot["meas_cell_list"]));
HANDLEPARSERCODE(parse_meas_report_desc(&cell_cfg.meas_cfg, cellroot["meas_report_desc"]));
}
cell_cfg.scell_list.resize(cellroot["scell_list"].getLength());

View File

@ -74,7 +74,7 @@ void rrc::init(const rrc_cfg_t& cfg_,
nof_si_messages = generate_sibs();
config_mac();
enb_mobility_cfg.reset(new mobility_cfg(&cfg));
enb_mobility_cfg.reset(new enb_mobility_handler(this));
bzero(&sr_sched, sizeof(sr_sched_t));
running = true;
@ -562,7 +562,7 @@ void rrc::read_pdu_pcch(uint8_t* payload, uint32_t buffer_size)
void rrc::ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique_byte_buffer_t rrc_container)
{
users.at(rnti)->handle_ho_preparation_complete(is_success, std::move(rrc_container));
users.at(rnti)->mobility_handler->handle_ho_preparation_complete(is_success, std::move(rrc_container));
}
/*******************************************************************************
@ -2100,6 +2100,7 @@ void rrc::ue::send_connection_reconf_new_bearer(const asn1::s1ap::erab_to_be_set
srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg;
bearer_cfg.direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH;
parent->mac->bearer_ue_cfg(rnti, lcid, &bearer_cfg);
current_sched_ue_cfg.ue_bearers[lcid] = bearer_cfg;
// Configure DRB in RLC
parent->rlc->add_bearer(rnti, lcid, srslte::make_rlc_config_t(drb_item.rlc_cfg));

View File

@ -52,6 +52,11 @@ uint32_t eci_to_cellid(uint32_t eci)
{
return eci & 0xFFu;
}
//! extract enb id from ECI
uint32_t eci_to_enbid(uint32_t eci)
{
return (eci - eci_to_cellid(eci)) >> 8u;
}
uint16_t compute_mac_i(uint16_t crnti,
uint32_t cellid,
uint16_t pci,
@ -250,8 +255,7 @@ struct compute_diff_generator {
src_end(src.end()),
target_it(target.begin()),
target_end(target.end())
{
}
{}
result_t next()
{
@ -415,7 +419,12 @@ asn1::rrc::quant_cfg_s* var_meas_cfg_t::add_quant_cfg(const asn1::rrc::quant_cfg
bool var_meas_cfg_t::compute_diff_meas_cfg(const var_meas_cfg_t& target_cfg, asn1::rrc::meas_cfg_s* meas_cfg) const
{
*meas_cfg = {};
// TODO: Create a flag to disable changing the "this" members (useful for transparent container)
// Shortcut in case this is the same as target
if (this == &target_cfg) {
return false;
}
// Set a MeasConfig in the RRC Connection Reconfiguration for HO.
compute_diff_meas_objs(target_cfg, meas_cfg);
compute_diff_report_cfgs(target_cfg, meas_cfg);
@ -507,7 +516,7 @@ void var_meas_cfg_t::compute_diff_meas_objs(const var_meas_cfg_t& target_cfg, me
break;
case rrc_details::diff_outcome_t::id_added: {
// case "entry with matching measObjectId doesn't exist in measObjToAddModList"
Info("HO: UE has now to measure activity of new frequency earfcn=%d.\n",
Info("UE has now to measure activity of new frequency earfcn=%d.\n",
result.target_it->meas_obj.meas_obj_eutra().carrier_freq);
auto& target_eutra = result.target_it->meas_obj.meas_obj_eutra();
auto& added_eutra = rrc_details::meascfg_add_meas_obj(meas_cfg, *result.target_it)->meas_obj.meas_obj_eutra();
@ -606,38 +615,75 @@ void var_meas_cfg_t::compute_diff_quant_cfg(const var_meas_cfg_t& target_cfg, as
}
}
/**
* Convert MeasCfg asn1 struct to var_meas_cfg_t
* @param meas_cfg
* @return
*/
var_meas_cfg_t var_meas_cfg_t::make(const asn1::rrc::meas_cfg_s& meas_cfg)
{
var_meas_cfg_t var;
if (meas_cfg.meas_id_to_add_mod_list_present) {
var.var_meas.meas_id_list_present = true;
var.var_meas.meas_id_list = meas_cfg.meas_id_to_add_mod_list;
}
if (meas_cfg.meas_obj_to_add_mod_list_present) {
var.var_meas.meas_obj_list_present = true;
var.var_meas.meas_obj_list = meas_cfg.meas_obj_to_add_mod_list;
}
if (meas_cfg.report_cfg_to_add_mod_list_present) {
var.var_meas.report_cfg_list_present = true;
var.var_meas.report_cfg_list = meas_cfg.report_cfg_to_add_mod_list;
}
if (meas_cfg.quant_cfg_present) {
var.var_meas.quant_cfg_present = true;
var.var_meas.quant_cfg = meas_cfg.quant_cfg;
}
if (meas_cfg.report_cfg_to_rem_list_present or meas_cfg.meas_obj_to_rem_list_present or
meas_cfg.meas_id_to_rem_list_present) {
srslte::logmap::get("RRC")->warning("Remove lists not handled by the var_meas_cfg_t method\n");
}
return var;
}
/*************************************************************************************************
* mobility_cfg class
************************************************************************************************/
rrc::mobility_cfg::mobility_cfg(const rrc_cfg_t* cfg_) : cfg(cfg_)
rrc::enb_mobility_handler::enb_mobility_handler(rrc* rrc_) : rrc_ptr(rrc_), cfg(&rrc_->cfg)
{
var_meas_cfg_t var_meas{};
cell_meas_cfg_list.resize(cfg->cell_list.size());
if (cfg->meas_cfg_present) {
// inserts all neighbor cells
for (const meas_cell_cfg_t& meascell : cfg->meas_cfg.meas_cells) {
var_meas.add_cell_cfg(meascell);
}
/* Create Template Cell VarMeasCfg List */
// insert all report cfgs
for (const report_cfg_eutra_s& reportcfg : cfg->meas_cfg.meas_reports) {
var_meas.add_report_cfg(reportcfg);
}
for (size_t i = 0; i < cfg->cell_list.size(); ++i) {
std::unique_ptr<var_meas_cfg_t> var_meas{new var_meas_cfg_t{}};
// insert all meas ids
// TODO: add this to the parser
if (var_meas.rep_cfgs().size() > 0) {
for (const auto& measobj : var_meas.meas_objs()) {
var_meas.add_measid_cfg(measobj.meas_obj_id, var_meas.rep_cfgs().begin()->report_cfg_id);
if (cfg->meas_cfg_present) {
// inserts all neighbor cells
for (const meas_cell_cfg_t& meascell : cfg->cell_list[i].meas_cfg.meas_cells) {
var_meas->add_cell_cfg(meascell);
}
// insert same report cfg for all cells
for (const report_cfg_eutra_s& reportcfg : cfg->cell_list[i].meas_cfg.meas_reports) {
var_meas->add_report_cfg(reportcfg);
}
// insert all meas ids
// TODO: add this to the parser
if (var_meas->rep_cfgs().size() > 0) {
for (const auto& measobj : var_meas->meas_objs()) {
var_meas->add_measid_cfg(measobj.meas_obj_id, var_meas->rep_cfgs().begin()->report_cfg_id);
}
}
// insert quantity config
var_meas->add_quant_cfg(cfg->cell_list[i].meas_cfg.quant_cfg);
}
// insert quantity config
var_meas.add_quant_cfg(cfg->meas_cfg.quant_cfg);
cell_meas_cfg_list[i].reset(var_meas.release());
}
current_meas_cfg = std::make_shared<var_meas_cfg_t>(var_meas);
}
/*************************************************************************************************
@ -652,8 +698,7 @@ rrc::ue::rrc_mobility::rrc_mobility(rrc::ue* outer_ue) :
rrc_log(outer_ue->parent->rrc_log),
source_ho_proc(this),
ue_var_meas(std::make_shared<var_meas_cfg_t>())
{
}
{}
//! Method to add Mobility Info to a RRC Connection Reconfiguration Message
bool rrc::ue::rrc_mobility::fill_conn_recfg_msg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn_recfg)
@ -664,21 +709,11 @@ bool rrc::ue::rrc_mobility::fill_conn_recfg_msg(asn1::rrc::rrc_conn_recfg_r8_ies
return false;
}
// Check if there has been any update
if (ue_var_meas.get() == cfg->current_meas_cfg.get()) {
return false;
}
asn1::rrc::meas_cfg_s* meas_cfg = &conn_recfg->meas_cfg;
bool updated = ue_var_meas->compute_diff_meas_cfg(*cfg->current_meas_cfg, meas_cfg);
// update ue var meas
ue_var_meas = cfg->current_meas_cfg;
if (updated) {
conn_recfg->meas_cfg_present = true;
return true;
}
return false;
// Check if there has been any update in ue_var_meas
cell_ctxt_t* pcell = rrc_ue->get_ue_cc_cfg(UE_PCELL_CC_IDX);
asn1::rrc::meas_cfg_s& meas_cfg = conn_recfg->meas_cfg;
conn_recfg->meas_cfg_present = update_ue_var_meas_cfg(*ue_var_meas, pcell->enb_cc_idx, &meas_cfg);
return conn_recfg->meas_cfg_present;
}
//! Method called whenever the eNB receives a MeasReport from the UE. In normal situations, an HO procedure is started
@ -727,8 +762,8 @@ void rrc::ue::rrc_mobility::handle_ue_meas_report(const meas_report_s& msg)
// TODO: check what to do here to take the decision.
// NOTE: for now just accept anything.
// HO going forward.
auto& L = rrc_enb->cfg.meas_cfg.meas_cells;
// Target cell to handover to was selected.
auto& L = rrc_enb->cfg.cell_list[rrc_ue->get_ue_cc_cfg(UE_PCELL_CC_IDX)->enb_cc_idx].meas_cfg.meas_cells;
uint32_t target_eci = std::find_if(L.begin(), L.end(), [pci](meas_cell_cfg_t& c) { return c.pci == pci; })->eci;
if (not source_ho_proc.launch(*measid_it, *obj_it, *rep_it, *cell_it, eutra_list[i], target_eci)) {
Error("Failed to start HO procedure, as it is already on-going\n");
@ -896,6 +931,33 @@ void rrc::ue::rrc_mobility::handle_ho_preparation_complete(bool is_success, srsl
source_ho_proc.trigger(sourceenb_ho_proc_t::ho_prep_result{is_success, std::move(container)});
}
bool rrc::ue::rrc_mobility::update_ue_var_meas_cfg(const asn1::rrc::meas_cfg_s& source_meas_cfg,
uint32_t target_enb_cc_idx,
asn1::rrc::meas_cfg_s* diff_meas_cfg)
{
// Generate equivalent VarMeasCfg
var_meas_cfg_t source_var = var_meas_cfg_t::make(source_meas_cfg);
// Compute difference measCfg and update UE VarMeasCfg
return update_ue_var_meas_cfg(source_var, target_enb_cc_idx, diff_meas_cfg);
}
bool rrc::ue::rrc_mobility::update_ue_var_meas_cfg(const var_meas_cfg_t& source_var_meas_cfg,
uint32_t target_enb_cc_idx,
asn1::rrc::meas_cfg_s* diff_meas_cfg)
{
// Fetch cell VarMeasCfg
auto& target_var_ptr = rrc_enb->enb_mobility_cfg->cell_meas_cfg_list[target_enb_cc_idx];
// Calculate difference between source and target VarMeasCfg
bool meas_cfg_present = source_var_meas_cfg.compute_diff_meas_cfg(*target_var_ptr, diff_meas_cfg);
// Update user varMeasCfg to target
rrc_ue->mobility_handler->ue_var_meas = target_var_ptr;
return meas_cfg_present;
}
/**
* TS 36.413, Section 8.4.6 - eNB Status Transfer
* Description: Send "eNBStatusTransfer" message from source eNB to MME

View File

@ -285,8 +285,6 @@ void s1ap::get_metrics(s1ap_metrics_t& m)
void s1ap::build_tai_cgi()
{
uint32_t plmn;
uint32_t tmp32;
uint16_t tmp16;
// TAI
s1ap_mccmnc_to_plmn(args.mcc, args.mnc, &plmn);

View File

@ -237,7 +237,7 @@ int test_correct_meascfg_calculation()
}
struct mobility_test_params {
enum class test_fail_at { success, wrong_measreport, concurrent_ho, ho_prep_failure } fail_at;
enum class test_fail_at { success, wrong_measreport, concurrent_ho, ho_prep_failure, recover } fail_at;
const char* to_string()
{
switch (fail_at) {
@ -249,15 +249,17 @@ struct mobility_test_params {
return "measreport while in handover";
case test_fail_at::ho_prep_failure:
return "ho preparation failure";
case test_fail_at::recover:
return "fail and success";
default:
return "none";
}
}
};
int test_mobility_class(mobility_test_params test_params)
int test_s1ap_mobility(mobility_test_params test_params)
{
printf("\n===== TEST: test_mobility_class() for event \"%s\" =====\n", test_params.to_string());
printf("\n===== TEST: test_s1ap_mobility() for event \"%s\" =====\n", test_params.to_string());
srslte::scoped_log<srslte::test_log_filter> rrc_log("RRC ");
srslte::timer_handler timers;
srslte::unique_byte_buffer_t pdu;
@ -266,11 +268,11 @@ int test_mobility_class(mobility_test_params test_params)
rrc_cfg_t cfg;
TESTASSERT(test_helpers::parse_default_cfg(&cfg, args) == SRSLTE_SUCCESS);
report_cfg_eutra_s rep = generate_rep1();
cfg.meas_cfg.meas_reports.push_back(rep);
cfg.cell_list[0].meas_cfg.meas_reports.push_back(rep);
meas_cell_cfg_t cell2 = generate_cell1();
cell2.pci = 2;
cell2.eci = 0x19C02;
cfg.meas_cfg.meas_cells.push_back(cell2);
cfg.cell_list[0].meas_cfg.meas_cells.push_back(cell2);
cfg.meas_cfg_present = true;
srsenb::rrc rrc;
@ -332,7 +334,7 @@ int test_mobility_class(mobility_test_params test_params)
return SRSLTE_SUCCESS;
}
/* Check HO Required was sent to S1AP */
/* Test Case: Check HO Required was sent to S1AP */
TESTASSERT(s1ap.last_ho_required.rnti == rnti);
TESTASSERT(s1ap.last_ho_required.target_eci == cell2.eci);
TESTASSERT(s1ap.last_ho_required.target_plmn.to_string() == "00101");
@ -360,9 +362,14 @@ int test_mobility_class(mobility_test_params test_params)
0x10, 0x00, 0x01, 0x00, 0x05, 0x00, 0xa7, 0xd0, 0xc1, 0xf6, 0xaf, 0x3e, 0x12, 0xcc,
0x86, 0x0d, 0x30, 0x00, 0x0b, 0x5a, 0x02, 0x17, 0x86, 0x00, 0x05, 0xa0, 0x20};
test_helpers::copy_msg_to_buffer(pdu, ho_cmd_rrc_container, sizeof(ho_cmd_rrc_container));
TESTASSERT(s1ap.last_enb_status.rnti != rnti);
rrc.ho_preparation_complete(rnti, true, std::move(pdu));
TESTASSERT(rrc_log->error_counter == 0);
asn1::rrc::dl_dcch_msg_s ho_cmd;
TESTASSERT(test_helpers::unpack_asn1(ho_cmd, pdcp.last_sdu.sdu));
auto& recfg_r8 = ho_cmd.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8();
TESTASSERT(recfg_r8.mob_ctrl_info_present);
return SRSLTE_SUCCESS;
}
@ -377,14 +384,14 @@ int main(int argc, char** argv)
argparse::parse_args(argc, argv);
TESTASSERT(test_correct_insertion() == 0);
TESTASSERT(test_correct_meascfg_calculation() == 0);
TESTASSERT(test_mobility_class(mobility_test_params{mobility_test_params::test_fail_at::wrong_measreport}) == 0);
TESTASSERT(test_mobility_class(mobility_test_params{mobility_test_params::test_fail_at::concurrent_ho}) == 0);
TESTASSERT(test_mobility_class(mobility_test_params{mobility_test_params::test_fail_at::ho_prep_failure}) == 0);
TESTASSERT(test_mobility_class(mobility_test_params{mobility_test_params::test_fail_at::success}) == 0);
TESTASSERT(test_s1ap_mobility(mobility_test_params{mobility_test_params::test_fail_at::wrong_measreport}) == 0);
TESTASSERT(test_s1ap_mobility(mobility_test_params{mobility_test_params::test_fail_at::concurrent_ho}) == 0);
TESTASSERT(test_s1ap_mobility(mobility_test_params{mobility_test_params::test_fail_at::ho_prep_failure}) == 0);
TESTASSERT(test_s1ap_mobility(mobility_test_params{mobility_test_params::test_fail_at::success}) == 0);
printf("\nSuccess\n");
srslte::byte_buffer_pool::get_instance()->cleanup();
return SRSLTE_SUCCESS;
}
}

View File

@ -74,7 +74,11 @@ public:
uint32_t target_eci;
srslte::plmn_id_t target_plmn;
srslte::unique_byte_buffer_t rrc_container;
} last_ho_required;
} last_ho_required = {};
struct enb_status_transfer_info {
uint16_t rnti;
std::vector<bearer_status_info> bearer_list;
} last_enb_status = {};
bool send_ho_required(uint16_t rnti,
uint32_t target_eci,
@ -130,6 +134,17 @@ int parse_default_cfg(rrc_cfg_t* rrc_cfg, srsenb::all_args_t& args)
return enb_conf_sections::parse_cfg_files(&args, rrc_cfg, &phy_cfg);
}
template <typename ASN1Type>
bool unpack_asn1(ASN1Type& asn1obj, const srslte::unique_byte_buffer_t& pdu)
{
asn1::cbit_ref bref{pdu->msg, pdu->N_bytes};
if (asn1obj.unpack(bref) != asn1::SRSASN_SUCCESS) {
srslte::logmap::get("TEST")->error("Failed to unpack ASN1 type\n");
return false;
}
return true;
}
void copy_msg_to_buffer(srslte::unique_byte_buffer_t& pdu, uint8_t* msg, size_t nof_bytes)
{
srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance();
@ -201,4 +216,4 @@ int bring_rrc_to_reconf_state(srsenb::rrc& rrc, srslte::timer_handler& timers, u
} // namespace test_helpers
#endif // SRSENB_TEST_HELPERS_H
#endif // SRSENB_TEST_HELPERS_H