mirror of https://github.com/pvnis/srsRAN_4G.git
Process HO complete in the background to avoid heap-after-use bug when PHY measurements are reported during a HO
rrc_meas refactor. Need to split commit Fix typo Temporal commit Apply rx_gain_offset to neighbour cell measurements srsLTE: modify TESTASSERT Macro to follow codeline SRSUE: prevent RRC from having serving cell in neighbour list SRSUE: DL HARQ does not need Time Aligment Timer. UL is disabled using PUCCH resources release SRSUE: extend intra-frequency to CA SCell SRSUE: fix confusing/ambiguous code in the RRC measurements and fix concurrency issue SRSUE: remove RRC measurement report triggers when measurements are modified or HO succesful SRSUE: fix compilation issues and Reest SIB indexes Fixes sync using incorrect cell configuration when search cell does not find a correct cell Small refactor to remove measurement report triggers always after removing measurement SRSUE: Removed SIC PSS from UE SRSUE: fix inter-frequency reestablishment and added more traces SRSUE: Fix compilation issuemaster
parent
d382c10948
commit
52716f8716
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSUE_MEASURE_RECV_H
|
||||
#define SRSUE_MEASURE_RECV_H
|
||||
|
||||
#include <srslte/srslte.h>
|
||||
|
||||
#include "srsue/hdr/phy/phy_common.h"
|
||||
|
||||
namespace srsue {
|
||||
namespace scell {
|
||||
// Class to perform cell measurements
|
||||
class measure
|
||||
{
|
||||
|
||||
// TODO: This class could early stop once the variance between the last N measurements is below 3GPP requirements
|
||||
|
||||
public:
|
||||
typedef enum { IDLE, MEASURE_OK, ERROR } ret_code;
|
||||
|
||||
~measure();
|
||||
void init(cf_t* buffer[SRSLTE_MAX_PORTS],
|
||||
srslte::log* log_h,
|
||||
uint32_t nof_rx_antennas,
|
||||
phy_common* worker_com,
|
||||
uint32_t nof_subframes = RSRP_MEASURE_NOF_FRAMES);
|
||||
void reset();
|
||||
void set_cell(srslte_cell_t cell);
|
||||
ret_code run_subframe(uint32_t sf_idx);
|
||||
ret_code run_multiple_subframes(cf_t* buffer, uint32_t offset, uint32_t sf_idx, uint32_t nof_sf);
|
||||
float rssi();
|
||||
float rsrp();
|
||||
float rsrq();
|
||||
float snr();
|
||||
float cfo();
|
||||
uint32_t frame_st_idx();
|
||||
void set_rx_gain_offset(float rx_gain_offset);
|
||||
|
||||
private:
|
||||
srslte::log* log_h;
|
||||
srslte_ue_dl_t ue_dl;
|
||||
srslte_ue_dl_cfg_t ue_dl_cfg;
|
||||
cf_t* buffer[SRSLTE_MAX_PORTS];
|
||||
uint32_t cnt;
|
||||
uint32_t nof_subframes;
|
||||
uint32_t current_prb;
|
||||
float rx_gain_offset;
|
||||
float mean_rsrp, mean_rsrq, mean_snr, mean_rssi, mean_cfo;
|
||||
uint32_t final_offset;
|
||||
const static int RSRP_MEASURE_NOF_FRAMES = 5;
|
||||
};
|
||||
|
||||
} // namespace scell
|
||||
} // namespace srsue
|
||||
|
||||
#endif // SRSUE_MEASURE_RECV_H
|
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
#ifndef SRSLTE_RRC_MEAS_H_
|
||||
#define SRSLTE_RRC_MEAS_H_
|
||||
|
||||
#include "srslte/asn1/rrc_asn1.h"
|
||||
#include "srslte/asn1/rrc_asn1_utils.h"
|
||||
#include "srslte/common/common.h"
|
||||
#include "srslte/common/log.h"
|
||||
#include "srslte/interfaces/ue_interfaces.h"
|
||||
#include "srsue/hdr/stack/rrc/rrc.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace srsue {
|
||||
|
||||
using namespace asn1::rrc;
|
||||
|
||||
typedef std::vector<phy_interface_rrc_lte::phy_cell_t> cell_triggered_t;
|
||||
|
||||
// RRC Measurements class
|
||||
class rrc::rrc_meas
|
||||
{
|
||||
public:
|
||||
rrc_meas(srslte::log* log_) : meas_cfg(&meas_report_list, log_), meas_report_list(&meas_cfg, log_), log_h(log_) {}
|
||||
void init(rrc* rrc_ptr);
|
||||
void reset();
|
||||
bool parse_meas_config(const rrc_conn_recfg_r8_ies_s* meas_config, bool is_ho_reest = false, uint32_t src_earfcn = 0);
|
||||
void run_tti(const uint32_t tti);
|
||||
void update_phy();
|
||||
float rsrp_filter(const float new_value, const float avg_value);
|
||||
float rsrq_filter(const float new_value, const float avg_value);
|
||||
|
||||
private:
|
||||
typedef struct {
|
||||
float rsrp;
|
||||
float rsrq;
|
||||
} phy_quant_t;
|
||||
|
||||
class var_meas_cfg;
|
||||
|
||||
class var_meas_report_list
|
||||
{
|
||||
public:
|
||||
var_meas_report_list(var_meas_cfg* meas_cfg_, srslte::log* log_) : meas_cfg(meas_cfg_), log_h(log_) {}
|
||||
void init(rrc* rrc);
|
||||
void generate_report(const uint32_t measId);
|
||||
void remove_all_varmeas_reports();
|
||||
void remove_varmeas_report(const uint32_t measId);
|
||||
bool is_timer_expired(const uint32_t measId);
|
||||
void set_measId(const uint32_t measId,
|
||||
const uint32_t carrier_freq,
|
||||
const report_cfg_eutra_s& report_cfg,
|
||||
const cell_triggered_t& cell_triggered_list);
|
||||
void upd_measId(const uint32_t measId, const cell_triggered_t& cell_triggered_list);
|
||||
cell_triggered_t get_measId_cells(const uint32_t measId);
|
||||
|
||||
private:
|
||||
class var_meas_report
|
||||
{
|
||||
public:
|
||||
uint32_t carrier_freq = 0;
|
||||
uint8_t nof_reports_sent = 0;
|
||||
cell_triggered_t cell_triggered_list = {};
|
||||
report_cfg_eutra_s report_cfg = {};
|
||||
srslte::timer_handler::unique_timer periodic_timer = {};
|
||||
};
|
||||
var_meas_cfg* meas_cfg = nullptr;
|
||||
srslte::log* log_h = nullptr;
|
||||
srslte::timer_handler* timers = nullptr;
|
||||
rrc* rrc_ptr = nullptr;
|
||||
std::map<uint32_t, var_meas_report> varMeasReportList;
|
||||
};
|
||||
|
||||
// The UE variable VarMeasConfig includes the accumulated configuration of the measurements to be performed by the
|
||||
// UE, covering intra-frequency, inter-frequency and inter-RAT mobility related measurements.
|
||||
class var_meas_cfg
|
||||
{
|
||||
public:
|
||||
var_meas_cfg(var_meas_report_list* meas_report_, srslte::log* log_) : meas_report(meas_report_), log_h(log_) {}
|
||||
void init(rrc* rrc);
|
||||
void reset();
|
||||
phy_quant_t get_filter_a();
|
||||
void remove_measId(const uint32_t measId);
|
||||
std::list<meas_obj_eutra_s> get_active_objects();
|
||||
void ho_reest_finish(const uint32_t src_earfcn, const uint32_t dst_earfcn);
|
||||
bool parse_meas_config(const meas_cfg_s* meas_config, bool is_ho_reest, uint32_t src_earfcn);
|
||||
void eval_triggers();
|
||||
void report_triggers();
|
||||
|
||||
private:
|
||||
void remove_varmeas_report(const uint32_t meas_id);
|
||||
|
||||
void measObject_removal(const meas_obj_to_rem_list_l& list);
|
||||
void measObject_addmod(const meas_obj_to_add_mod_list_l& list);
|
||||
void reportConfig_removal(const report_cfg_to_rem_list_l& list);
|
||||
void reportConfig_addmod(const report_cfg_to_add_mod_list_l& list);
|
||||
void measId_removal(const meas_id_to_rem_list_l& list);
|
||||
void measId_addmod(const meas_id_to_add_mod_list_l& list);
|
||||
void quantity_config(const quant_cfg_s& cfg);
|
||||
void log_debug_trigger_value(const eutra_event_s::event_id_c_& e);
|
||||
|
||||
static bool is_rsrp(report_cfg_eutra_s::trigger_quant_opts::options q);
|
||||
|
||||
class cell_trigger_state
|
||||
{
|
||||
public:
|
||||
void event_condition(const bool enter, const bool exit);
|
||||
bool is_enter_equal(const uint32_t nof_tti);
|
||||
bool is_exit_equal(const uint32_t nof_tti);
|
||||
|
||||
private:
|
||||
uint32_t nof_tti_enter = 0;
|
||||
uint32_t nof_tti_exit = 0;
|
||||
};
|
||||
|
||||
// varMeasConfig data
|
||||
std::map<uint32_t, meas_id_to_add_mod_s> measIdList; // Uses MeasId as key
|
||||
std::map<uint32_t, meas_obj_eutra_s> measObjectsList; // Uses MeasObjectId as key
|
||||
std::map<uint32_t, report_cfg_eutra_s> reportConfigList; // Uses ReportConfigId as key
|
||||
|
||||
phy_quant_t filter_a = {};
|
||||
float s_measure_value = 0.0;
|
||||
|
||||
// trigger counters. First key is measId, second key is cell id (pci)
|
||||
// It is safe to use [] operator in this double-map because all members are uint32_t
|
||||
std::map<uint32_t, std::map<uint32_t, cell_trigger_state> > trigger_state;
|
||||
|
||||
var_meas_report_list* meas_report = nullptr;
|
||||
srslte::log* log_h = nullptr;
|
||||
rrc* rrc_ptr = nullptr;
|
||||
};
|
||||
|
||||
std::mutex meas_cfg_mutex;
|
||||
var_meas_cfg meas_cfg;
|
||||
var_meas_report_list meas_report_list;
|
||||
srslte::log* log_h = nullptr;
|
||||
rrc* rrc_ptr = nullptr;
|
||||
|
||||
// Static functions
|
||||
static uint8_t value_to_range(const report_cfg_eutra_s::trigger_quant_opts::options q, float value);
|
||||
static float range_to_value(const report_cfg_eutra_s::trigger_quant_opts::options q, const uint8_t range);
|
||||
static uint8_t offset_val(const meas_obj_eutra_s& meas_obj);
|
||||
static asn1::dyn_array<cells_to_add_mod_s>::iterator find_pci_in_meas_obj(meas_obj_eutra_s& meas_obj, uint32_t pci);
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
#endif // SRSLTE_SRSUE_HDR_STACK_RRC_RRC_MEAS_H_
|
@ -1,233 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srsue/hdr/phy/scell/measure.h"
|
||||
|
||||
#define Error(fmt, ...) \
|
||||
if (SRSLTE_DEBUG_ENABLED) \
|
||||
log_h->error(fmt, ##__VA_ARGS__)
|
||||
#define Warning(fmt, ...) \
|
||||
if (SRSLTE_DEBUG_ENABLED) \
|
||||
log_h->warning(fmt, ##__VA_ARGS__)
|
||||
#define Info(fmt, ...) \
|
||||
if (SRSLTE_DEBUG_ENABLED) \
|
||||
log_h->info(fmt, ##__VA_ARGS__)
|
||||
#define Debug(fmt, ...) \
|
||||
if (SRSLTE_DEBUG_ENABLED) \
|
||||
log_h->debug(fmt, ##__VA_ARGS__)
|
||||
|
||||
namespace srsue {
|
||||
namespace scell {
|
||||
void measure::init(cf_t* buffer[SRSLTE_MAX_PORTS],
|
||||
srslte::log* log_h,
|
||||
uint32_t nof_rx_antennas,
|
||||
phy_common* worker_com,
|
||||
uint32_t nof_subframes)
|
||||
|
||||
{
|
||||
this->log_h = log_h;
|
||||
this->nof_subframes = nof_subframes;
|
||||
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
this->buffer[i] = buffer[i];
|
||||
}
|
||||
|
||||
if (srslte_ue_dl_init(&ue_dl, this->buffer, SRSLTE_MAX_PRB, nof_rx_antennas)) {
|
||||
Error("SYNC: Initiating ue_dl_measure\n");
|
||||
return;
|
||||
}
|
||||
worker_com->set_ue_dl_cfg(&ue_dl_cfg);
|
||||
ue_dl_cfg.chest_cfg.rsrp_neighbour = true;
|
||||
reset();
|
||||
}
|
||||
|
||||
measure::~measure()
|
||||
{
|
||||
srslte_ue_dl_free(&ue_dl);
|
||||
}
|
||||
|
||||
void measure::reset()
|
||||
{
|
||||
cnt = 0;
|
||||
mean_rsrp = 0;
|
||||
mean_rsrq = 0;
|
||||
mean_snr = 0;
|
||||
mean_rssi = 0;
|
||||
mean_cfo = 0;
|
||||
}
|
||||
|
||||
void measure::set_cell(srslte_cell_t cell)
|
||||
{
|
||||
current_prb = cell.nof_prb;
|
||||
if (srslte_ue_dl_set_cell(&ue_dl, cell)) {
|
||||
Error("SYNC: Setting cell: initiating ue_dl_measure\n");
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
float measure::rssi()
|
||||
{
|
||||
return srslte_convert_power_to_dB(mean_rssi);
|
||||
}
|
||||
|
||||
float measure::rsrp()
|
||||
{
|
||||
return srslte_convert_power_to_dBm(mean_rsrp) - rx_gain_offset;
|
||||
}
|
||||
|
||||
float measure::rsrq()
|
||||
{
|
||||
return srslte_convert_power_to_dB(mean_rsrq);
|
||||
}
|
||||
|
||||
float measure::snr()
|
||||
{
|
||||
return mean_snr;
|
||||
}
|
||||
|
||||
float measure::cfo()
|
||||
{
|
||||
return mean_cfo;
|
||||
}
|
||||
|
||||
uint32_t measure::frame_st_idx()
|
||||
{
|
||||
return final_offset;
|
||||
}
|
||||
|
||||
void measure::set_rx_gain_offset(float rx_gain_offset_)
|
||||
{
|
||||
rx_gain_offset = rx_gain_offset_;
|
||||
}
|
||||
|
||||
measure::ret_code measure::run_multiple_subframes(cf_t* input_buffer, uint32_t offset, uint32_t sf_idx, uint32_t max_sf)
|
||||
{
|
||||
uint32_t sf_len = (uint32_t)SRSLTE_SF_LEN_PRB(current_prb);
|
||||
|
||||
ret_code ret = IDLE;
|
||||
|
||||
int sf_start = offset - sf_len / 2;
|
||||
while (sf_start < 0 && sf_idx < max_sf) {
|
||||
Info("INTRA: sf_start=%d, sf_idx=%d\n", sf_start, sf_idx);
|
||||
sf_start += sf_len;
|
||||
sf_idx++;
|
||||
}
|
||||
|
||||
#ifdef FINE_TUNE_OFFSET_WITH_RS
|
||||
float max_rsrp = -200;
|
||||
int best_test_sf_start = 0;
|
||||
int test_sf_start = 0;
|
||||
bool found_best = false;
|
||||
|
||||
// Fine-tune sf_start using RS
|
||||
for (uint32_t n = 0; n < 5; n++) {
|
||||
|
||||
test_sf_start = sf_start - 2 + n;
|
||||
if (test_sf_start >= 0) {
|
||||
|
||||
cf_t* buf_m[SRSLTE_MAX_PORTS];
|
||||
buf_m[0] = &input_buffer[test_sf_start];
|
||||
|
||||
uint32_t cfi;
|
||||
if (srslte_ue_dl_decode_fft_estimate_noguru(&ue_dl, buf_m, sf_idx, &cfi)) {
|
||||
Error("MEAS: Measuring RSRP: Estimating channel\n");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
float rsrp = srslte_chest_dl_get_rsrp(&ue_dl.chest);
|
||||
if (rsrp > max_rsrp) {
|
||||
max_rsrp = rsrp;
|
||||
best_test_sf_start = test_sf_start;
|
||||
found_best = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug("INTRA: fine-tuning sf_start: %d, found_best=%d, rem_sf=%d\n", sf_start, found_best, nof_sf);
|
||||
|
||||
sf_start = found_best ? best_test_sf_start : sf_start;
|
||||
#endif
|
||||
|
||||
if (sf_start >= 0 && sf_start < (int)(sf_len * max_sf)) {
|
||||
|
||||
uint32_t nof_sf = (sf_len * max_sf - sf_start) / sf_len;
|
||||
|
||||
final_offset = (uint32_t)sf_start;
|
||||
|
||||
for (uint32_t i = 0; i < nof_sf; i++) {
|
||||
memcpy(buffer[0], &input_buffer[sf_start + i * sf_len], sizeof(cf_t) * sf_len);
|
||||
ret = run_subframe((sf_idx + i) % 10);
|
||||
if (ret != IDLE) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (ret != ERROR) {
|
||||
return MEASURE_OK;
|
||||
}
|
||||
} else {
|
||||
Error("INTRA: not running because sf_start=%d, offset=%d, sf_len*max_sf=%d*%d\n", sf_start, offset, sf_len, max_sf);
|
||||
ret = ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
measure::ret_code measure::run_subframe(uint32_t sf_idx)
|
||||
{
|
||||
srslte_dl_sf_cfg_t sf_cfg;
|
||||
ZERO_OBJECT(sf_cfg);
|
||||
sf_cfg.tti = sf_idx;
|
||||
|
||||
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, &sf_cfg, &ue_dl_cfg)) {
|
||||
log_h->error("SYNC: Measuring RSRP: Estimating channel\n");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
float rsrp = ue_dl.chest_res.rsrp_neigh;
|
||||
float rsrq = ue_dl.chest_res.rsrq;
|
||||
float snr = ue_dl.chest_res.snr_db;
|
||||
float cfo = ue_dl.chest_res.cfo;
|
||||
float rssi = srslte_vec_avg_power_cf(buffer[0], (uint32_t)SRSLTE_SF_LEN_PRB(current_prb));
|
||||
|
||||
if (cnt == 0) {
|
||||
mean_rsrp = rsrp;
|
||||
mean_rsrq = rsrq;
|
||||
mean_snr = snr;
|
||||
mean_rssi = rssi;
|
||||
mean_cfo = cfo;
|
||||
} else {
|
||||
mean_rsrp = SRSLTE_VEC_CMA(rsrp, mean_rsrp, cnt);
|
||||
mean_rsrq = SRSLTE_VEC_CMA(rsrq, mean_rsrq, cnt);
|
||||
mean_snr = SRSLTE_VEC_CMA(snr, mean_snr, cnt);
|
||||
mean_rssi = SRSLTE_VEC_CMA(rssi, mean_rssi, cnt);
|
||||
mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, cnt);
|
||||
}
|
||||
cnt++;
|
||||
|
||||
log_h->debug(
|
||||
"SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", cnt, nof_subframes, sf_idx, rsrp, snr);
|
||||
|
||||
if (cnt >= nof_subframes) {
|
||||
return MEASURE_OK;
|
||||
} else {
|
||||
return IDLE;
|
||||
}
|
||||
}
|
||||
} // namespace scell
|
||||
} // namespace srsue
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,983 @@
|
||||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srslte/asn1/rrc_asn1.h"
|
||||
#include "srslte/common/buffer_pool.h"
|
||||
#include "srslte/common/log_filter.h"
|
||||
#include "srslte/common/test_common.h"
|
||||
#include "srslte/upper/pdcp.h"
|
||||
#include "srsue/hdr/stack/rrc/rrc.h"
|
||||
#include "srsue/hdr/stack/rrc/rrc_meas.h"
|
||||
#include "srsue/hdr/stack/upper/nas.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace asn1::rrc;
|
||||
using namespace srsue;
|
||||
|
||||
class phy_test final : public phy_interface_rrc_lte
|
||||
{
|
||||
public:
|
||||
void set_serving_cell(uint32_t pci, uint32_t earfcn)
|
||||
{
|
||||
serving_pci = pci;
|
||||
serving_earfcn = earfcn;
|
||||
}
|
||||
|
||||
// Not implemented methods
|
||||
void set_config(srslte::phy_cfg_t& config,
|
||||
uint32_t cc_idx = 0,
|
||||
uint32_t earfcn = 0,
|
||||
srslte_cell_t* cell_info = nullptr) override
|
||||
{
|
||||
}
|
||||
void set_config_tdd(srslte_tdd_config_t& tdd_config) override {}
|
||||
void set_config_mbsfn_sib2(srslte::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) override {}
|
||||
void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) override {}
|
||||
void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) override {}
|
||||
cell_search_ret_t cell_search(phy_cell_t* cell) override { return {}; }
|
||||
bool cell_is_camping() override { return false; }
|
||||
bool cell_select(phy_cell_t* cell = nullptr) override { return false; }
|
||||
void reset() override {}
|
||||
void enable_pregen_signals(bool enable) override {}
|
||||
|
||||
void set_cells_to_meas(uint32_t earfcn, std::set<uint32_t>& pci) override
|
||||
{
|
||||
freqs_started.insert(earfcn);
|
||||
cells_started[earfcn] = pci;
|
||||
}
|
||||
void meas_stop() override
|
||||
{
|
||||
freqs_started.clear();
|
||||
cells_started.clear();
|
||||
}
|
||||
|
||||
void reset_test()
|
||||
{
|
||||
meas_reset_called = false;
|
||||
meas_stop();
|
||||
}
|
||||
|
||||
uint32_t meas_nof_freqs() { return freqs_started.size(); }
|
||||
|
||||
uint32_t meas_nof_cells(uint32_t earfcn)
|
||||
{
|
||||
if (cells_started.count(earfcn)) {
|
||||
return cells_started[earfcn].size();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool meas_freq_started(uint32_t earfcn) { return freqs_started.count(earfcn) > 0; }
|
||||
bool meas_cell_started(uint32_t earfcn, uint32_t pci)
|
||||
{
|
||||
if (cells_started.count(earfcn)) {
|
||||
return cells_started[earfcn].count(pci) > 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool meas_reset_called = false;
|
||||
std::set<uint32_t> freqs_started;
|
||||
std::map<uint32_t, std::set<uint32_t> > cells_started;
|
||||
uint32_t serving_pci = 0;
|
||||
uint32_t serving_earfcn = 0;
|
||||
};
|
||||
|
||||
class nas_test : public srsue::nas
|
||||
{
|
||||
public:
|
||||
nas_test(srslte::log* log_, srslte::timer_handler* t) : srsue::nas(log_, t) {}
|
||||
bool is_attached() override { return false; }
|
||||
};
|
||||
|
||||
class pdcp_test : public srslte::pdcp
|
||||
{
|
||||
public:
|
||||
pdcp_test(srslte::log* log_, srslte::timer_handler* t) : srslte::pdcp(t, log_) {}
|
||||
void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, bool blocking = false) override
|
||||
{
|
||||
ul_dcch_msg_s ul_dcch_msg;
|
||||
asn1::cbit_ref bref(sdu->msg, sdu->N_bytes);
|
||||
if (ul_dcch_msg.unpack(bref) != asn1::SRSASN_SUCCESS or
|
||||
ul_dcch_msg.msg.type().value != ul_dcch_msg_type_c::types_opts::c1) {
|
||||
return;
|
||||
}
|
||||
switch (ul_dcch_msg.msg.c1().type()) {
|
||||
case ul_dcch_msg_type_c::c1_c_::types::rrc_conn_recfg_complete:
|
||||
if (!error) {
|
||||
error = !expecting_reconf_complete;
|
||||
}
|
||||
received_reconf_complete = true;
|
||||
break;
|
||||
case ul_dcch_msg_type_c::c1_c_::types::meas_report:
|
||||
if (!error) {
|
||||
error = expecting_reconf_complete;
|
||||
}
|
||||
if (!expecting_reconf_complete) {
|
||||
meas_res = ul_dcch_msg.msg.c1().meas_report().crit_exts.c1().meas_report_r8().meas_results;
|
||||
meas_res_received = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool get_meas_res(meas_results_s& meas_res_)
|
||||
{
|
||||
if (meas_res_received) {
|
||||
meas_res_ = meas_res;
|
||||
meas_res_received = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool get_error() { return error; }
|
||||
bool expecting_reconf_complete = false;
|
||||
bool received_reconf_complete = false;
|
||||
|
||||
private:
|
||||
bool error = false;
|
||||
meas_results_s meas_res = {};
|
||||
bool meas_res_received = false;
|
||||
};
|
||||
|
||||
static srslte::timer_handler global_timers;
|
||||
|
||||
class rrc_test : public rrc
|
||||
{
|
||||
public:
|
||||
rrc_test(srslte::log* log_) : rrc(log_)
|
||||
{
|
||||
pool = srslte::byte_buffer_pool::get_instance();
|
||||
nastest = new nas_test(log_, &global_timers);
|
||||
pdcptest = new pdcp_test(log_, &global_timers);
|
||||
};
|
||||
~rrc_test()
|
||||
{
|
||||
delete nastest;
|
||||
delete pdcptest;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
rrc::init(&phytest, nullptr, nullptr, pdcptest, nastest, nullptr, nullptr, &global_timers, nullptr, {});
|
||||
}
|
||||
|
||||
void run_tti(uint32_t tti_)
|
||||
{
|
||||
global_timers.step_all();
|
||||
rrc::run_tti(tti_);
|
||||
}
|
||||
|
||||
// Set RRC in state RRC_CONNECTED
|
||||
void connect()
|
||||
{
|
||||
dl_ccch_msg_s dl_ccch_msg = {};
|
||||
dl_ccch_msg.msg.set_c1();
|
||||
dl_ccch_msg.msg.c1().set_rrc_conn_setup();
|
||||
dl_ccch_msg.msg.c1().rrc_conn_setup().crit_exts.set_c1().set_rrc_conn_setup_r8();
|
||||
send_ccch_msg(dl_ccch_msg);
|
||||
run_tti(tti++);
|
||||
}
|
||||
|
||||
bool send_meas_cfg(rrc_conn_recfg_r8_ies_s& rrc_conn_recfg)
|
||||
{
|
||||
phytest.reset_test();
|
||||
pdcptest->received_reconf_complete = false;
|
||||
|
||||
dl_dcch_msg_s dl_dcch_msg = {};
|
||||
dl_dcch_msg.msg.set_c1();
|
||||
dl_dcch_msg.msg.c1().set_rrc_conn_recfg();
|
||||
dl_dcch_msg.msg.c1().rrc_conn_recfg().crit_exts.set_c1().set_rrc_conn_recfg_r8();
|
||||
dl_dcch_msg.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8() = rrc_conn_recfg;
|
||||
send_dcch_msg(dl_dcch_msg);
|
||||
|
||||
pdcptest->expecting_reconf_complete = true;
|
||||
run_tti(tti++);
|
||||
pdcptest->expecting_reconf_complete = false;
|
||||
return !pdcptest->get_error() && pdcptest->received_reconf_complete;
|
||||
}
|
||||
|
||||
void send_ccch_msg(dl_ccch_msg_s& dl_ccch_msg)
|
||||
{
|
||||
srslte::unique_byte_buffer_t pdu = srslte::allocate_unique_buffer(*pool, true);
|
||||
;
|
||||
asn1::bit_ref bref(pdu->msg, pdu->get_tailroom());
|
||||
dl_ccch_msg.pack(bref);
|
||||
bref.align_bytes_zero();
|
||||
pdu->N_bytes = (uint32_t)bref.distance_bytes(pdu->msg);
|
||||
pdu->set_timestamp();
|
||||
write_pdu(0, std::move(pdu));
|
||||
}
|
||||
|
||||
void send_dcch_msg(dl_dcch_msg_s& dl_dcch_msg)
|
||||
{
|
||||
srslte::unique_byte_buffer_t pdu = srslte::allocate_unique_buffer(*pool, true);
|
||||
;
|
||||
asn1::bit_ref bref(pdu->msg, pdu->get_tailroom());
|
||||
dl_dcch_msg.pack(bref);
|
||||
bref.align_bytes_zero();
|
||||
pdu->N_bytes = (uint32_t)bref.distance_bytes(pdu->msg);
|
||||
pdu->set_timestamp();
|
||||
write_pdu(1, std::move(pdu));
|
||||
}
|
||||
|
||||
void set_serving_cell(uint32_t pci, uint32_t earfcn)
|
||||
{
|
||||
std::vector<rrc_interface_phy_lte::phy_meas_t> phy_meas = {};
|
||||
rrc_interface_phy_lte::phy_meas_t meas = {};
|
||||
meas.pci = pci;
|
||||
meas.earfcn = earfcn;
|
||||
phy_meas.push_back(meas); // neighbour cell
|
||||
new_cell_meas(phy_meas);
|
||||
run_tti(1);
|
||||
phytest.set_serving_cell(pci, earfcn);
|
||||
rrc::set_serving_cell({pci, earfcn}, false);
|
||||
}
|
||||
|
||||
bool has_neighbour_cell(const uint32_t earfcn, const uint32_t pci) { return rrc::has_neighbour_cell(earfcn, pci); }
|
||||
|
||||
bool get_meas_res(meas_results_s& meas_res) { return pdcptest->get_meas_res(meas_res); }
|
||||
|
||||
phy_test phytest;
|
||||
|
||||
private:
|
||||
pdcp_test* pdcptest;
|
||||
nas_test* nastest;
|
||||
uint32_t tti = 0;
|
||||
srslte::byte_buffer_pool* pool = nullptr;
|
||||
};
|
||||
|
||||
// Test Cell sear
|
||||
int cell_select_test()
|
||||
{
|
||||
srslte::log_filter log1("RRC_MEAS");
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
log1.set_hex_limit(-1);
|
||||
|
||||
printf("==========================================================\n");
|
||||
printf("====== Cell Select Testing ===============\n");
|
||||
printf("==========================================================\n");
|
||||
|
||||
rrc_test rrctest(&log1);
|
||||
rrctest.init();
|
||||
rrctest.connect();
|
||||
|
||||
// Add a first serving cell
|
||||
rrctest.set_serving_cell(1, 1);
|
||||
|
||||
// Add a second serving cell
|
||||
rrctest.set_serving_cell(2, 2);
|
||||
|
||||
// Select the second serving cell
|
||||
rrctest.set_serving_cell(2, 2);
|
||||
|
||||
TESTASSERT(!rrctest.has_neighbour_cell(2, 2));
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
// Tests the measObject configuration and the successful activation of PHY cells to search for
|
||||
int meas_obj_test()
|
||||
{
|
||||
srslte::log_filter log1("RRC_MEAS");
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
log1.set_hex_limit(-1);
|
||||
|
||||
printf("==========================================================\n");
|
||||
printf("====== Object Configuration Testing ===============\n");
|
||||
printf("==========================================================\n");
|
||||
|
||||
rrc_test rrctest(&log1);
|
||||
rrctest.init();
|
||||
rrctest.connect();
|
||||
|
||||
// Configure serving cell. First add neighbour, then set it as serving cell
|
||||
rrctest.set_serving_cell(1, 1);
|
||||
|
||||
rrc_conn_recfg_r8_ies_s rrc_conn_recfg = {};
|
||||
rrc_conn_recfg.meas_cfg_present = true;
|
||||
meas_cfg_s& meas_cfg = rrc_conn_recfg.meas_cfg;
|
||||
|
||||
log1.info("Test1: Remove non-existing measObject, reportConfig and measId\n");
|
||||
meas_cfg = {};
|
||||
meas_cfg.meas_id_to_rem_list.push_back(3);
|
||||
meas_cfg.meas_obj_to_rem_list.push_back(3);
|
||||
meas_cfg.report_cfg_to_rem_list.push_back(3);
|
||||
meas_cfg.meas_id_to_rem_list_present = true;
|
||||
meas_cfg.meas_obj_to_rem_list_present = true;
|
||||
|
||||
// Just test it doesn't crash
|
||||
TESTASSERT(rrctest.send_meas_cfg(rrc_conn_recfg));
|
||||
TESTASSERT(rrctest.phytest.meas_nof_freqs() == 0);
|
||||
|
||||
log1.info("Test2: Add measId pointing to non-existing measObject or reportConfig\n");
|
||||
meas_cfg = {};
|
||||
meas_id_to_add_mod_s m = {};
|
||||
m.meas_obj_id = 1;
|
||||
m.report_cfg_id = 1;
|
||||
m.meas_id = 1;
|
||||
meas_cfg.meas_id_to_add_mod_list.push_back(m);
|
||||
meas_cfg.meas_id_to_add_mod_list_present = true;
|
||||
|
||||
// Just test it doesn't crash
|
||||
TESTASSERT(rrctest.send_meas_cfg(rrc_conn_recfg));
|
||||
TESTASSERT(rrctest.phytest.meas_nof_freqs() == 0);
|
||||
|
||||
log1.info("Test3: Add meaObject and report of unsupported type. Setup a supported report for later use\n");
|
||||
meas_cfg = {};
|
||||
meas_obj_to_add_mod_s obj = {};
|
||||
obj.meas_obj.set_meas_obj_utra();
|
||||
meas_cfg.meas_obj_to_add_mod_list.push_back(obj);
|
||||
meas_cfg.meas_obj_to_add_mod_list_present = true;
|
||||
report_cfg_to_add_mod_s rep = {};
|
||||
rep.report_cfg_id = 2;
|
||||
rep.report_cfg.set_report_cfg_inter_rat().trigger_type.set_periodical().purpose =
|
||||
report_cfg_inter_rat_s::trigger_type_c_::periodical_s_::purpose_opts::report_strongest_cells;
|
||||
rep.report_cfg.report_cfg_inter_rat().report_interv.value = report_interv_opts::ms640;
|
||||
rep.report_cfg.report_cfg_inter_rat().report_amount = report_cfg_inter_rat_s::report_amount_opts::r1;
|
||||
meas_cfg.report_cfg_to_add_mod_list.push_back(rep);
|
||||
rep = {};
|
||||
rep.report_cfg_id = 1;
|
||||
rep.report_cfg.set_report_cfg_eutra();
|
||||
rep.report_cfg.report_cfg_eutra().report_interv = report_interv_opts::ms120;
|
||||
rep.report_cfg.report_cfg_eutra().report_amount = report_cfg_eutra_s::report_amount_opts::r1;
|
||||
rep.report_cfg.report_cfg_eutra().report_quant.value = report_cfg_eutra_s::report_quant_opts::both;
|
||||
rep.report_cfg.report_cfg_eutra().trigger_quant.value = report_cfg_eutra_s::trigger_quant_opts::rsrp;
|
||||
rep.report_cfg.report_cfg_eutra().trigger_type.set_event().event_id.set_event_a1().a1_thres.set_thres_rsrp();
|
||||
rep.report_cfg.report_cfg_eutra().trigger_type.event().time_to_trigger.value = time_to_trigger_opts::ms640;
|
||||
meas_cfg.report_cfg_to_add_mod_list.push_back(rep);
|
||||
meas_cfg.report_cfg_to_add_mod_list_present = true;
|
||||
|
||||
// Just test it doesn't crash
|
||||
TESTASSERT(rrctest.send_meas_cfg(rrc_conn_recfg));
|
||||
TESTASSERT(rrctest.phytest.meas_nof_freqs() == 0);
|
||||
|
||||
log1.info("Test4: Add 2 measObjects and 2 measId both pointing to the same measObject \n");
|
||||
meas_cfg = {};
|
||||
for (int i = 0; i < 2; i++) {
|
||||
m = {};
|
||||
m.meas_obj_id = 1; // same object
|
||||
m.report_cfg_id = 1;
|
||||
m.meas_id = 1 + i; // add 2 different measIds
|
||||
meas_cfg.meas_id_to_add_mod_list.push_back(m);
|
||||
}
|
||||
meas_cfg.meas_id_to_add_mod_list_present = true;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
obj = {};
|
||||
obj.meas_obj_id = 1 + i;
|
||||
obj.meas_obj.set_meas_obj_eutra();
|
||||
obj.meas_obj.meas_obj_eutra().carrier_freq = 1 + i;
|
||||
obj.meas_obj.meas_obj_eutra().allowed_meas_bw.value = allowed_meas_bw_opts::mbw6;
|
||||
if (i == 1) { // 2nd object has cells, 1st one doesn't
|
||||
for (int j = 1; j <= 4; j++) {
|
||||
cells_to_add_mod_s cell = {};
|
||||
cell.pci = 10 + j;
|
||||
cell.cell_idx = j;
|
||||
cell.cell_individual_offset.value = q_offset_range_opts::db0;
|
||||
obj.meas_obj.meas_obj_eutra().cells_to_add_mod_list.push_back(cell);
|
||||
}
|
||||
obj.meas_obj.meas_obj_eutra().cells_to_add_mod_list_present = true;
|
||||
}
|
||||
meas_cfg.meas_obj_to_add_mod_list.push_back(obj);
|
||||
}
|
||||
meas_cfg.meas_obj_to_add_mod_list_present = true;
|
||||
|
||||
TESTASSERT(rrctest.send_meas_cfg(rrc_conn_recfg));
|
||||
// Test we configure 1 frequency with no cells
|
||||
TESTASSERT(rrctest.phytest.meas_nof_freqs() == 1);
|
||||
TESTASSERT(rrctest.phytest.meas_freq_started(1));
|
||||
TESTASSERT(rrctest.phytest.meas_nof_cells(1) == 0);
|
||||
|
||||
log1.info("Test5: Add existing objects and measId. Now add measId for 2nd cell\n");
|
||||
meas_cfg = {};
|
||||
m = {};
|
||||
m.meas_obj_id = 2; // same object
|
||||
m.report_cfg_id = 1;
|
||||
m.meas_id = 3;
|
||||
meas_cfg.meas_id_to_add_mod_list.push_back(m);
|
||||
meas_cfg.meas_id_to_add_mod_list_present = true;
|
||||
rrctest.phytest.reset_test();
|
||||
TESTASSERT(rrctest.send_meas_cfg(rrc_conn_recfg));
|
||||
|
||||
// Test we configure 2 frequency. 2nd has 4 cells
|
||||
TESTASSERT(rrctest.phytest.meas_nof_freqs() == 2);
|
||||
TESTASSERT(rrctest.phytest.meas_freq_started(1));
|
||||
TESTASSERT(rrctest.phytest.meas_freq_started(2));
|
||||
TESTASSERT(rrctest.phytest.meas_nof_cells(1) == 0);
|
||||
TESTASSERT(rrctest.phytest.meas_nof_cells(2) == 4);
|
||||
for (int j = 1; j <= 4; j++) {
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(2, 10 + j));
|
||||
}
|
||||
|
||||
// Reconfigure 2nd object only, we should see 8 cells now
|
||||
log1.info("Test6: Add 1 cell to 1st object. Mixed add/mod and removal command.\n");
|
||||
meas_cfg = {};
|
||||
meas_cfg.meas_obj_to_add_mod_list_present = true;
|
||||
|
||||
// 1st object add 1 cell, none existed
|
||||
obj = {};
|
||||
obj.meas_obj_id = 1;
|
||||
obj.meas_obj.set(meas_obj_to_add_mod_s::meas_obj_c_::types_opts::meas_obj_eutra);
|
||||
obj.meas_obj.meas_obj_eutra().carrier_freq = 1;
|
||||
obj.meas_obj.meas_obj_eutra().cells_to_add_mod_list_present = true;
|
||||
obj.meas_obj.meas_obj_eutra().allowed_meas_bw.value = allowed_meas_bw_opts::mbw6;
|
||||
cells_to_add_mod_s cell = {};
|
||||
cell.cell_idx = 1;
|
||||
cell.pci = 1;
|
||||
cell.cell_individual_offset.value = q_offset_range_opts::db0;
|
||||
obj.meas_obj.meas_obj_eutra().cells_to_add_mod_list.push_back(cell);
|
||||
meas_cfg.meas_obj_to_add_mod_list.push_back(obj);
|
||||
|
||||
// 2nd object remove 3 cells (1 non-existing)
|
||||
obj = {};
|
||||
obj.meas_obj_id = 2;
|
||||
obj.meas_obj.set(meas_obj_to_add_mod_s::meas_obj_c_::types_opts::meas_obj_eutra);
|
||||
obj.meas_obj.meas_obj_eutra().carrier_freq = 2;
|
||||
obj.meas_obj.meas_obj_eutra().cells_to_rem_list.push_back(2);
|
||||
obj.meas_obj.meas_obj_eutra().cells_to_rem_list.push_back(4);
|
||||
obj.meas_obj.meas_obj_eutra().cells_to_rem_list.push_back(6);
|
||||
obj.meas_obj.meas_obj_eutra().cells_to_rem_list_present = true;
|
||||
|
||||
// 2nd object add 5 cells, 1 existing, 1 just removed, 3 new
|
||||
uint32_t new_idx[5] = {2, 3, 5, 6};
|
||||
for (int j = 0; j < 4; j++) {
|
||||
cell = {};
|
||||
cell.pci = 20 + j + 1;
|
||||
cell.cell_idx = new_idx[j];
|
||||
cell.cell_individual_offset.value = q_offset_range_opts::db0;
|
||||
obj.meas_obj.meas_obj_eutra().cells_to_add_mod_list.push_back(cell);
|
||||
}
|
||||
obj.meas_obj.meas_obj_eutra().allowed_meas_bw.value = allowed_meas_bw_opts::mbw6;
|
||||
obj.meas_obj.meas_obj_eutra().cells_to_add_mod_list_present = true;
|
||||
meas_cfg.meas_obj_to_add_mod_list.push_back(obj);
|
||||
|
||||
rrctest.phytest.reset_test();
|
||||
TESTASSERT(rrctest.send_meas_cfg(rrc_conn_recfg));
|
||||
TESTASSERT(rrctest.phytest.meas_nof_cells(1) == 1);
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(1, 1));
|
||||
TESTASSERT(rrctest.phytest.meas_nof_cells(2) == 5);
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(2, 11)); // wasn't changed
|
||||
TESTASSERT(!rrctest.phytest.meas_cell_started(2, 12)); // was removed
|
||||
TESTASSERT(!rrctest.phytest.meas_cell_started(2, 14)); // was removed
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(2, 21)); // was added
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(2, 22)); // was updated
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(2, 23)); // was added
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(2, 24)); // was added
|
||||
|
||||
log1.info("Test7: PHY finds new neigbhours in frequency 1 and 2, check RRC instructs to search them\n");
|
||||
std::vector<rrc_interface_phy_lte::phy_meas_t> phy_meas = {};
|
||||
phy_meas.push_back({0, 0, 1, 31});
|
||||
phy_meas.push_back({-1, 0, 1, 32});
|
||||
phy_meas.push_back({-2, 0, 1, 33});
|
||||
phy_meas.push_back({-3, 0, 1, 34});
|
||||
rrctest.new_cell_meas(phy_meas);
|
||||
rrctest.run_tti(1);
|
||||
phy_meas = {};
|
||||
phy_meas.push_back({-4, 0, 1, 35});
|
||||
phy_meas.push_back({-5, 0, 1, 36});
|
||||
phy_meas.push_back({-6, 0, 1, 37});
|
||||
phy_meas.push_back({1, 0, 1, 30});
|
||||
phy_meas.push_back({0, 0, 2, 31});
|
||||
rrctest.new_cell_meas(phy_meas);
|
||||
rrctest.run_tti(1);
|
||||
|
||||
TESTASSERT(rrctest.phytest.meas_nof_cells(1) == 8);
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(1, 1));
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(1, 30));
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(1, 31));
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(1, 32));
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(1, 33));
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(1, 34));
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(1, 35));
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(1, 36));
|
||||
TESTASSERT(rrctest.phytest.meas_nof_cells(2) == 6);
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(2, 11)); // wasn't changed
|
||||
TESTASSERT(!rrctest.phytest.meas_cell_started(2, 12)); // was removed
|
||||
TESTASSERT(!rrctest.phytest.meas_cell_started(2, 14)); // was removed
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(2, 21)); // was added
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(2, 22)); // was updated
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(2, 23)); // was added
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(2, 24)); // was added
|
||||
TESTASSERT(rrctest.phytest.meas_cell_started(2, 31));
|
||||
|
||||
log1.info("Test8: Simulate a Release (reset() call) make sure resets correctly\n");
|
||||
rrctest.init();
|
||||
rrctest.run_tti(1);
|
||||
rrctest.connect();
|
||||
rrctest.run_tti(1);
|
||||
|
||||
log1.info("Test9: Config removal\n");
|
||||
meas_cfg = {};
|
||||
meas_cfg.meas_obj_to_rem_list.push_back(1);
|
||||
meas_cfg.meas_obj_to_rem_list.push_back(2);
|
||||
meas_cfg.meas_obj_to_rem_list_present = true;
|
||||
meas_cfg.report_cfg_to_rem_list.push_back(1);
|
||||
meas_cfg.report_cfg_to_rem_list.push_back(2);
|
||||
meas_cfg.report_cfg_to_rem_list_present = true;
|
||||
meas_cfg.meas_id_to_rem_list.push_back(1);
|
||||
meas_cfg.meas_id_to_rem_list.push_back(2);
|
||||
meas_cfg.meas_id_to_rem_list_present = true;
|
||||
printf("==========================================================\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void config_default_report_test(rrc_conn_recfg_r8_ies_s& rrc_conn_recfg,
|
||||
eutra_event_s::event_id_c_ event_id,
|
||||
time_to_trigger_e time_trigger,
|
||||
uint32_t hyst,
|
||||
report_cfg_eutra_s::report_amount_e_ report_amount,
|
||||
report_interv_e report_interv)
|
||||
{
|
||||
rrc_conn_recfg.meas_cfg_present = true;
|
||||
meas_cfg_s& meas_cfg = rrc_conn_recfg.meas_cfg;
|
||||
|
||||
meas_cfg = {};
|
||||
meas_id_to_add_mod_s m = {};
|
||||
m.meas_obj_id = 4;
|
||||
m.report_cfg_id = 1;
|
||||
m.meas_id = 1;
|
||||
meas_cfg.meas_id_to_add_mod_list.push_back(m);
|
||||
if (event_id.type() == eutra_event_s::event_id_c_::types::event_a3) {
|
||||
m = {};
|
||||
m.meas_obj_id = 6;
|
||||
m.report_cfg_id = 1;
|
||||
m.meas_id = 2;
|
||||
meas_cfg.meas_id_to_add_mod_list.push_back(m);
|
||||
}
|
||||
meas_cfg.meas_id_to_add_mod_list_present = true;
|
||||
|
||||
meas_obj_to_add_mod_s obj = {};
|
||||
obj.meas_obj.set_meas_obj_eutra();
|
||||
obj.meas_obj.meas_obj_eutra().carrier_freq = 1;
|
||||
obj.meas_obj.meas_obj_eutra().allowed_meas_bw.value = allowed_meas_bw_opts::mbw6;
|
||||
obj.meas_obj_id = 4;
|
||||
meas_cfg.meas_obj_to_add_mod_list.push_back(obj);
|
||||
obj = {};
|
||||
obj.meas_obj.set_meas_obj_eutra();
|
||||
obj.meas_obj.meas_obj_eutra().carrier_freq = 2;
|
||||
obj.meas_obj.meas_obj_eutra().allowed_meas_bw.value = allowed_meas_bw_opts::mbw6;
|
||||
obj.meas_obj_id = 6;
|
||||
meas_cfg.meas_obj_to_add_mod_list.push_back(obj);
|
||||
meas_cfg.meas_obj_to_add_mod_list_present = true;
|
||||
|
||||
// Disable avearging
|
||||
meas_cfg.quant_cfg_present = true;
|
||||
meas_cfg.quant_cfg.quant_cfg_eutra_present = true;
|
||||
meas_cfg.quant_cfg.quant_cfg_eutra.filt_coef_rsrp_present = true;
|
||||
meas_cfg.quant_cfg.quant_cfg_eutra.filt_coef_rsrp.value = filt_coef_opts::fc0;
|
||||
|
||||
// Report event
|
||||
report_cfg_to_add_mod_s rep = {};
|
||||
rep.report_cfg_id = 1;
|
||||
rep.report_cfg.set_report_cfg_eutra();
|
||||
rep.report_cfg.report_cfg_eutra().trigger_type.set_event();
|
||||
rep.report_cfg.report_cfg_eutra().trigger_type.event().event_id = event_id;
|
||||
rep.report_cfg.report_cfg_eutra().trigger_type.event().time_to_trigger = time_trigger;
|
||||
rep.report_cfg.report_cfg_eutra().trigger_type.event().hysteresis = hyst;
|
||||
rep.report_cfg.report_cfg_eutra().trigger_quant.value = report_cfg_eutra_s::trigger_quant_opts::rsrp;
|
||||
rep.report_cfg.report_cfg_eutra().report_quant.value = report_cfg_eutra_s::report_quant_opts::same_as_trigger_quant;
|
||||
rep.report_cfg.report_cfg_eutra().max_report_cells = 8;
|
||||
rep.report_cfg.report_cfg_eutra().report_interv.value = report_interv;
|
||||
rep.report_cfg.report_cfg_eutra().report_amount.value = report_amount;
|
||||
meas_cfg.report_cfg_to_add_mod_list.push_back(rep);
|
||||
meas_cfg.report_cfg_to_add_mod_list_present = true;
|
||||
}
|
||||
|
||||
void send_report(rrc_test& rrctest,
|
||||
const std::vector<float> rsrp,
|
||||
const std::vector<uint32_t> earfcn,
|
||||
const std::vector<uint32_t> pci)
|
||||
{
|
||||
std::vector<rrc_interface_phy_lte::phy_meas_t> phy_meas = {};
|
||||
for (uint32_t i = 0; i < pci.size(); i++) {
|
||||
float r = rsrp[0];
|
||||
if (rsrp.size() == pci.size()) {
|
||||
r = rsrp[i];
|
||||
}
|
||||
uint32_t e = earfcn[0];
|
||||
if (earfcn.size() == pci.size()) {
|
||||
e = earfcn[i];
|
||||
}
|
||||
phy_meas.push_back({r, -5, e, pci[i]});
|
||||
}
|
||||
rrctest.new_cell_meas(phy_meas);
|
||||
rrctest.run_tti(1);
|
||||
}
|
||||
|
||||
void middle_condition(rrc_test& rrctest,
|
||||
const eutra_event_s::event_id_c_ event_id,
|
||||
const uint32_t hyst,
|
||||
const uint32_t earfcn,
|
||||
const std::vector<uint32_t> pci)
|
||||
{
|
||||
if (event_id.type() == eutra_event_s::event_id_c_::types_opts::event_a1) {
|
||||
float rsrp_th = -140 + event_id.event_a1().a1_thres.thres_rsrp() + 0.5 * hyst;
|
||||
send_report(rrctest, {rsrp_th - (float)1e-2}, {earfcn}, pci);
|
||||
} else {
|
||||
float offset = 0.5 * event_id.event_a3().a3_offset;
|
||||
std::vector<float> rsrp = {};
|
||||
rsrp.reserve(pci.size());
|
||||
for (uint32_t i = 0; i < pci.size(); i++) {
|
||||
if (i == 0) {
|
||||
rsrp.push_back(-60);
|
||||
} else {
|
||||
rsrp.push_back(-60 + offset + 0.5 * hyst - (float)1e-2);
|
||||
}
|
||||
}
|
||||
send_report(rrctest, rsrp, {0, earfcn}, pci);
|
||||
}
|
||||
}
|
||||
|
||||
void enter_condition(rrc_test& rrctest,
|
||||
const eutra_event_s::event_id_c_ event_id,
|
||||
const uint32_t hyst,
|
||||
const uint32_t earfcn,
|
||||
const std::vector<uint32_t> pci)
|
||||
{
|
||||
if (event_id.type() == eutra_event_s::event_id_c_::types_opts::event_a1) {
|
||||
float rsrp_th = -140 + event_id.event_a1().a1_thres.thres_rsrp() + 0.5 * hyst;
|
||||
send_report(rrctest, {rsrp_th + (float)1e-2}, {earfcn}, pci);
|
||||
} else {
|
||||
float offset = 0.5 * event_id.event_a3().a3_offset;
|
||||
std::vector<float> rsrp = {};
|
||||
rsrp.reserve(pci.size());
|
||||
for (uint32_t i = 0; i < pci.size(); i++) {
|
||||
if (i == 0) {
|
||||
rsrp.push_back(-60);
|
||||
} else {
|
||||
rsrp.push_back(-60 + offset + 0.01 * pci[i] + 0.5 * hyst + (float)1e-2);
|
||||
}
|
||||
}
|
||||
send_report(rrctest, rsrp, {0, earfcn}, pci);
|
||||
}
|
||||
}
|
||||
|
||||
void no_condition(rrc_test& rrctest, const std::vector<uint32_t>& earfcn, const std::vector<uint32_t>& pci)
|
||||
{
|
||||
std::vector<float> rsrp = {};
|
||||
rsrp.reserve(pci.size());
|
||||
for (uint32_t i = 0; i < pci.size(); i++) {
|
||||
rsrp.push_back(-60.0f);
|
||||
}
|
||||
send_report(rrctest, rsrp, earfcn, pci);
|
||||
}
|
||||
|
||||
void exit_condition(rrc_test& rrctest,
|
||||
const eutra_event_s::event_id_c_ event_id,
|
||||
const uint32_t hyst,
|
||||
const uint32_t earfcn,
|
||||
const std::vector<uint32_t> pci)
|
||||
{
|
||||
if (event_id.type() == eutra_event_s::event_id_c_::types_opts::event_a1) {
|
||||
float rsrp_th_leave = -140 + event_id.event_a1().a1_thres.thres_rsrp() - 0.5 * hyst;
|
||||
send_report(rrctest, {rsrp_th_leave - (float)1e-2}, {earfcn}, pci);
|
||||
} else {
|
||||
float offset = 0.5 * event_id.event_a3().a3_offset;
|
||||
std::vector<float> rsrp = {};
|
||||
rsrp.reserve(pci.size());
|
||||
for (uint32_t i = 0; i < pci.size(); i++) {
|
||||
if (i == 0) {
|
||||
rsrp.push_back(-60);
|
||||
} else {
|
||||
rsrp.push_back(-60 + offset - 0.5 * hyst - (float)1e-2);
|
||||
}
|
||||
}
|
||||
send_report(rrctest, rsrp, {0, earfcn}, pci);
|
||||
}
|
||||
}
|
||||
|
||||
// Test A1-event reporting and management of report amount and interval
|
||||
int a1event_report_test(uint32_t a1_rsrp_th,
|
||||
time_to_trigger_e time_trigger,
|
||||
uint32_t hyst,
|
||||
report_cfg_eutra_s::report_amount_e_ report_amount,
|
||||
report_interv_e report_interv)
|
||||
{
|
||||
|
||||
srslte::log_filter log1("RRC_MEAS");
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
log1.set_hex_limit(-1);
|
||||
|
||||
printf("==========================================================\n");
|
||||
printf("============ Report Testing A1 ===============\n");
|
||||
printf("==========================================================\n");
|
||||
|
||||
rrc_test rrctest(&log1);
|
||||
rrctest.init();
|
||||
rrctest.connect();
|
||||
|
||||
// Configure serving cell. First add neighbour, then set it as serving cell
|
||||
rrctest.set_serving_cell(1, 1);
|
||||
|
||||
// default report configuration
|
||||
rrc_conn_recfg_r8_ies_s rrc_conn_recfg = {};
|
||||
eutra_event_s::event_id_c_ event_id = {};
|
||||
|
||||
event_id.set_event_a1();
|
||||
event_id.event_a1().a1_thres.set_thres_rsrp();
|
||||
event_id.event_a1().a1_thres.thres_rsrp() = a1_rsrp_th;
|
||||
|
||||
config_default_report_test(rrc_conn_recfg, event_id, time_trigger, hyst, report_amount, report_interv);
|
||||
|
||||
TESTASSERT(rrctest.send_meas_cfg(rrc_conn_recfg));
|
||||
|
||||
meas_results_s meas_res = {};
|
||||
|
||||
int ttt_iters = time_trigger.to_number() + 1;
|
||||
|
||||
// Entering condition during half timeToTrigger, should not trigger measurement
|
||||
for (int i = 0; i < ttt_iters / 2; i++) {
|
||||
log1.info("Report %d/%d enter condition is true\n", i, ttt_iters / 2);
|
||||
enter_condition(rrctest, event_id, hyst, 0, {1, 2});
|
||||
// Check doesn't generate measurement report
|
||||
TESTASSERT(!rrctest.get_meas_res(meas_res));
|
||||
}
|
||||
|
||||
log1.info("Report leaving enter condition\n");
|
||||
// Not satisfy entering condition for 1 TTI
|
||||
middle_condition(rrctest, event_id, hyst, 0, {1});
|
||||
TESTASSERT(!rrctest.get_meas_res(meas_res));
|
||||
|
||||
// Should go again all timeToTrigger, should not trigger measurement until end
|
||||
for (int i = 0; i < ttt_iters; i++) {
|
||||
log1.info("Report %d/%d enter condition is true\n", i, ttt_iters);
|
||||
enter_condition(rrctest, event_id, hyst, 0, {1, 2});
|
||||
if (i < ttt_iters - 1) {
|
||||
// Check doesn't generate measurement report
|
||||
TESTASSERT(!rrctest.get_meas_res(meas_res));
|
||||
}
|
||||
}
|
||||
|
||||
// Check report is correct: RSRP=32, RSRQ=30 and measId=1
|
||||
TESTASSERT(rrctest.get_meas_res(meas_res));
|
||||
TESTASSERT(meas_res.meas_id == 1);
|
||||
TESTASSERT(!meas_res.meas_result_neigh_cells_present);
|
||||
TESTASSERT(meas_res.meas_result_pcell.rsrp_result == 32);
|
||||
TESTASSERT(meas_res.meas_result_pcell.rsrq_result == 30);
|
||||
|
||||
// Test multiple reports are sent if report_amount > 1
|
||||
if (report_amount.to_number() > 1) {
|
||||
// Trigger again entering condition for the same cell it shouldn't trigger a new report, just keep sending the
|
||||
// periodic reports without restarting counter
|
||||
for (int i = 0; i < ttt_iters; i++) {
|
||||
log1.info("Report %d/%d enter condition is true\n", i, ttt_iters);
|
||||
enter_condition(rrctest, event_id, hyst, 0, {1});
|
||||
}
|
||||
// Do not expect report if timer not expired
|
||||
TESTASSERT(!rrctest.get_meas_res(meas_res));
|
||||
// Wait to generate all reports
|
||||
for (int i = 0; i < report_amount.to_number() - 1; i++) {
|
||||
log1.info("Testing report %d/%d\n", i, report_amount.to_number());
|
||||
int interval = report_interv.to_number();
|
||||
if (i == 0) {
|
||||
// already stepped these iterations
|
||||
interval -= ttt_iters;
|
||||
}
|
||||
for (int j = 0; j < interval; j++) {
|
||||
if (j == 0 && i > report_amount.to_number() - 3) {
|
||||
// Exit the enter condition in the last one, should still send the last report
|
||||
middle_condition(rrctest, event_id, hyst, 0, {1});
|
||||
} else {
|
||||
log1.info("Stepping timer %d/%d\n", j, interval);
|
||||
rrctest.run_tti(1);
|
||||
}
|
||||
if (j < interval - 1) {
|
||||
// Do not expect report if timer not expired
|
||||
TESTASSERT(!rrctest.get_meas_res(meas_res));
|
||||
} else {
|
||||
// expect 1 report every interval ms
|
||||
TESTASSERT(rrctest.get_meas_res(meas_res));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Do not expect more reports
|
||||
for (int j = 0; j < report_interv.to_number(); j++) {
|
||||
rrctest.run_tti(1);
|
||||
TESTASSERT(!rrctest.get_meas_res(meas_res));
|
||||
}
|
||||
// Trigger again condition
|
||||
for (int i = 0; i < ttt_iters; i++) {
|
||||
log1.info("Report %d/%d enter condition is true\n", i, ttt_iters);
|
||||
enter_condition(rrctest, event_id, hyst, 0, {1});
|
||||
}
|
||||
// Do not expect report
|
||||
TESTASSERT(!rrctest.get_meas_res(meas_res));
|
||||
|
||||
// Leaving condition for timeToTrigger
|
||||
for (int i = 0; i < ttt_iters; i++) {
|
||||
log1.info("Report %d/%d leaving condition is true\n", i, ttt_iters);
|
||||
exit_condition(rrctest, event_id, hyst, 0, {1});
|
||||
// Check doesn't generate measurement report
|
||||
TESTASSERT(!rrctest.get_meas_res(meas_res));
|
||||
}
|
||||
// Trigger again condition
|
||||
for (int i = 0; i < ttt_iters; i++) {
|
||||
log1.info("Report %d/%d enter condition is true\n", i, ttt_iters);
|
||||
enter_condition(rrctest, event_id, hyst, 0, {1});
|
||||
}
|
||||
// Expect report
|
||||
TESTASSERT(rrctest.get_meas_res(meas_res));
|
||||
}
|
||||
|
||||
printf("==========================================================\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test A3-event reporting and management of report amount and interval
|
||||
int a3event_report_test(uint32_t a3_offset, uint32_t hyst, bool report_on_leave)
|
||||
{
|
||||
|
||||
srslte::log_filter log1("RRC_MEAS");
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
log1.set_hex_limit(-1);
|
||||
|
||||
printf("==========================================================\n");
|
||||
printf("============ Report Testing A3 ===============\n");
|
||||
printf("==========================================================\n");
|
||||
|
||||
rrc_test rrctest(&log1);
|
||||
rrctest.init();
|
||||
rrctest.connect();
|
||||
|
||||
// Configure serving cell. First add neighbour, then set it as serving cell
|
||||
rrctest.set_serving_cell(1, 1);
|
||||
|
||||
// default report configuration
|
||||
rrc_conn_recfg_r8_ies_s rrc_conn_recfg = {};
|
||||
eutra_event_s::event_id_c_ event_id = {};
|
||||
|
||||
event_id.set_event_a3();
|
||||
event_id.event_a3().a3_offset = a3_offset;
|
||||
event_id.event_a3().report_on_leave = report_on_leave;
|
||||
|
||||
config_default_report_test(rrc_conn_recfg,
|
||||
event_id,
|
||||
time_to_trigger_opts::ms0,
|
||||
hyst,
|
||||
report_cfg_eutra_s::report_amount_opts::r1,
|
||||
report_interv_opts::ms120);
|
||||
|
||||
TESTASSERT(rrctest.send_meas_cfg(rrc_conn_recfg));
|
||||
|
||||
meas_results_s meas_res = {};
|
||||
|
||||
log1.info("Test no-enter condition and no trigger report \n");
|
||||
no_condition(rrctest, {0}, {1});
|
||||
TESTASSERT(!rrctest.get_meas_res(meas_res));
|
||||
|
||||
no_condition(rrctest, {0, 1}, {1, 0});
|
||||
TESTASSERT(!rrctest.get_meas_res(meas_res));
|
||||
|
||||
log1.info("Test enter condition triggers report. 1 neighbour cell in enter + 1 in exit \n");
|
||||
float offset = 0.5 * event_id.event_a3().a3_offset;
|
||||
std::vector<float> rsrp = {};
|
||||
rsrp.push_back(-60 + offset + 0.5 * hyst + (float)1e-2);
|
||||
rsrp.push_back(-60 + offset - 0.5 * hyst - (float)1e-2);
|
||||
send_report(rrctest, rsrp, {1, 1}, {0, 3});
|
||||
|
||||
// Check report is correct: RSRP=34, RSRQ=0 and measId=1
|
||||
TESTASSERT(rrctest.get_meas_res(meas_res));
|
||||
TESTASSERT(meas_res.meas_id == 1);
|
||||
TESTASSERT(meas_res.meas_result_pcell.rsrp_result == 81);
|
||||
TESTASSERT(meas_res.meas_result_pcell.rsrq_result == 30);
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells_present);
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells.meas_result_list_eutra().size() == 1);
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells.meas_result_list_eutra()[0].pci == 0);
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells.meas_result_list_eutra()[0].meas_result.rsrp_result ==
|
||||
81 + (hyst + a3_offset) / 2);
|
||||
|
||||
// Next iteration in entering state does not trigger another report
|
||||
log1.info("Test enter condition for the same cell does not trigger report\n");
|
||||
rrctest.run_tti(1);
|
||||
TESTASSERT(!rrctest.get_meas_res(meas_res));
|
||||
|
||||
log1.info("Test enter condition for different earfcn triggers report\n");
|
||||
enter_condition(rrctest, event_id, hyst, 2, {1, 3});
|
||||
TESTASSERT(rrctest.get_meas_res(meas_res));
|
||||
TESTASSERT(meas_res.meas_id == 2);
|
||||
TESTASSERT(meas_res.meas_result_pcell.rsrp_result == 81);
|
||||
TESTASSERT(meas_res.meas_result_pcell.rsrq_result == 30);
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells_present);
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells.meas_result_list_eutra().size() == 1);
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells.meas_result_list_eutra()[0].pci == 3);
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells.meas_result_list_eutra()[0].meas_result.rsrp_result ==
|
||||
81 + (hyst + a3_offset) / 2);
|
||||
|
||||
// if a new cell enters conditions then expect another report
|
||||
log1.info("Test a new cell enter condition triggers report\n");
|
||||
enter_condition(rrctest, event_id, hyst, 1, {1, 3});
|
||||
TESTASSERT(rrctest.get_meas_res(meas_res));
|
||||
TESTASSERT(meas_res.meas_id == 1);
|
||||
TESTASSERT(meas_res.meas_result_pcell.rsrp_result == 81);
|
||||
TESTASSERT(meas_res.meas_result_pcell.rsrq_result == 30);
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells_present);
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells.meas_result_list_eutra().size() == 2);
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells.meas_result_list_eutra()[0].pci ==
|
||||
3); // should be ordered by rsrp, which is proportional to pci in enter_condition()
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells.meas_result_list_eutra()[0].meas_result.rsrp_result ==
|
||||
81 + (hyst + a3_offset) / 2);
|
||||
|
||||
// cell pci=0 exists condition
|
||||
log1.info("Test exit condition\n");
|
||||
exit_condition(rrctest, event_id, hyst, 1, {1, 0});
|
||||
if (report_on_leave) {
|
||||
TESTASSERT(rrctest.get_meas_res(meas_res));
|
||||
}
|
||||
|
||||
// 2 enters again, now expect report again
|
||||
log1.info("Test trigger again the cell that exited\n");
|
||||
enter_condition(rrctest, event_id, hyst, 1, {1, 0});
|
||||
TESTASSERT(rrctest.get_meas_res(meas_res));
|
||||
TESTASSERT(meas_res.meas_id == 1);
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells_present);
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells.meas_result_list_eutra().size() == 2);
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells.meas_result_list_eutra()[0].pci == 3);
|
||||
TESTASSERT(meas_res.meas_result_neigh_cells.meas_result_list_eutra()[0].meas_result.rsrp_result ==
|
||||
81 + (hyst + a3_offset) / 2);
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
TESTASSERT(cell_select_test() == SRSLTE_SUCCESS);
|
||||
TESTASSERT(meas_obj_test() == SRSLTE_SUCCESS);
|
||||
TESTASSERT(
|
||||
a1event_report_test(
|
||||
30, time_to_trigger_opts::ms40, 3, report_cfg_eutra_s::report_amount_opts::r1, report_interv_opts::ms120) ==
|
||||
SRSLTE_SUCCESS);
|
||||
TESTASSERT(
|
||||
a1event_report_test(
|
||||
30, time_to_trigger_opts::ms0, 3, report_cfg_eutra_s::report_amount_opts::r1, report_interv_opts::ms120) ==
|
||||
SRSLTE_SUCCESS);
|
||||
TESTASSERT(
|
||||
a1event_report_test(
|
||||
30, time_to_trigger_opts::ms40, 3, report_cfg_eutra_s::report_amount_opts::r8, report_interv_opts::ms120) ==
|
||||
SRSLTE_SUCCESS);
|
||||
TESTASSERT(a3event_report_test(6, 3, true) == SRSLTE_SUCCESS);
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue