mirror of https://github.com/PentHertz/srsLTE.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 issue
This commit is contained in:
parent
d382c10948
commit
52716f8716
|
@ -80,6 +80,7 @@ option(ENABLE_TTCN3 "Enable TTCN3 test binaries" OFF)
|
|||
option(BUILD_STATIC "Attempt to statically link external deps" OFF)
|
||||
option(RPATH "Enable RPATH" OFF)
|
||||
option(ENABLE_ASAN "Enable gcc/clang address sanitizer" OFF)
|
||||
option(ENABLE_GCOV "Enable gcc/clang address sanitizer" OFF)
|
||||
option(ENABLE_MSAN "Enable clang memory sanitizer" OFF)
|
||||
option(ENABLE_TIDY "Enable clang tidy" OFF)
|
||||
|
||||
|
@ -435,6 +436,11 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
|
|||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -fno-omit-frame-pointer -fPIE -pie")
|
||||
endif (ENABLE_MSAN AND CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
|
||||
if (ENABLE_GCOV)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||
endif (ENABLE_GCOV)
|
||||
|
||||
endif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
|
|
|
@ -188,6 +188,8 @@ public:
|
|||
|
||||
void stop() { impl()->stop(); }
|
||||
|
||||
void clear() { impl()->clear(); }
|
||||
|
||||
void release()
|
||||
{
|
||||
impl()->clear();
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#ifndef SRSLTE_UE_INTERFACES_H
|
||||
#define SRSLTE_UE_INTERFACES_H
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "rrc_interface_types.h"
|
||||
|
@ -133,9 +134,17 @@ public:
|
|||
class rrc_interface_phy_lte
|
||||
{
|
||||
public:
|
||||
virtual void in_sync() = 0;
|
||||
virtual void out_of_sync() = 0;
|
||||
virtual void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn = -1, int pci = -1) = 0;
|
||||
// Measurement object from phy
|
||||
typedef struct {
|
||||
float rsrp;
|
||||
float rsrq;
|
||||
uint32_t earfcn;
|
||||
uint32_t pci;
|
||||
} phy_meas_t;
|
||||
|
||||
virtual void in_sync() = 0;
|
||||
virtual void out_of_sync() = 0;
|
||||
virtual void new_cell_meas(std::vector<phy_meas_t>& meas) = 0;
|
||||
};
|
||||
|
||||
// RRC interface for NAS
|
||||
|
@ -273,6 +282,7 @@ public:
|
|||
virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0;
|
||||
virtual bool has_bearer(uint32_t lcid) = 0;
|
||||
virtual bool has_data(const uint32_t lcid) = 0;
|
||||
virtual bool is_suspended(const uint32_t lcid) = 0;
|
||||
virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, bool blocking = true) = 0;
|
||||
};
|
||||
|
||||
|
@ -514,7 +524,6 @@ typedef struct {
|
|||
uint32_t estimator_fil_order = 4;
|
||||
float snr_to_cqi_offset = 0.0f;
|
||||
std::string sss_algorithm = "full";
|
||||
bool sic_pss_enabled = false;
|
||||
float rx_gain_offset = 62;
|
||||
bool pdsch_csi_enabled = true;
|
||||
bool pdsch_8bit_decoder = false;
|
||||
|
@ -582,10 +591,6 @@ public:
|
|||
class phy_interface_rrc_lte
|
||||
{
|
||||
public:
|
||||
virtual void get_current_cell(srslte_cell_t* cell, uint32_t* current_earfcn = NULL) = 0;
|
||||
virtual uint32_t get_current_earfcn() = 0;
|
||||
virtual uint32_t get_current_pci() = 0;
|
||||
|
||||
virtual void set_config(srslte::phy_cfg_t& config,
|
||||
uint32_t cc_idx = 0,
|
||||
uint32_t earfcn = 0,
|
||||
|
@ -596,9 +601,8 @@ public:
|
|||
virtual void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) = 0;
|
||||
|
||||
/* Measurements interface */
|
||||
virtual void meas_reset() = 0;
|
||||
virtual int meas_start(uint32_t earfcn, int pci = -1) = 0;
|
||||
virtual int meas_stop(uint32_t earfcn, int pci = -1) = 0;
|
||||
virtual void set_cells_to_meas(uint32_t earfcn, std::set<uint32_t>& pci) = 0;
|
||||
virtual void meas_stop() = 0;
|
||||
|
||||
typedef struct {
|
||||
enum { CELL_FOUND = 0, CELL_NOT_FOUND, ERROR } found;
|
||||
|
@ -606,8 +610,8 @@ public:
|
|||
} cell_search_ret_t;
|
||||
|
||||
typedef struct {
|
||||
srslte_cell_t cell;
|
||||
uint32_t earfcn;
|
||||
uint32_t pci;
|
||||
uint32_t earfcn;
|
||||
} phy_cell_t;
|
||||
|
||||
/* Cell search and selection procedures */
|
||||
|
|
|
@ -58,6 +58,7 @@ public:
|
|||
|
||||
// MAC interface
|
||||
bool has_data(const uint32_t lcid);
|
||||
bool is_suspended(const uint32_t lcid);
|
||||
uint32_t get_buffer_state(const uint32_t lcid);
|
||||
uint32_t get_total_mch_buffer_state(uint32_t lcid);
|
||||
int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes);
|
||||
|
|
|
@ -221,17 +221,17 @@ public:
|
|||
|
||||
bool suspend()
|
||||
{
|
||||
if (is_suspended) {
|
||||
if (suspended) {
|
||||
return false;
|
||||
}
|
||||
is_suspended = true;
|
||||
suspended = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pops all PDUs from queue and calls write_pdu() method for the bearer type
|
||||
bool resume()
|
||||
{
|
||||
if (!is_suspended) {
|
||||
if (!suspended) {
|
||||
return false;
|
||||
}
|
||||
pdu_t p;
|
||||
|
@ -240,13 +240,13 @@ public:
|
|||
write_pdu(p.payload, p.nof_bytes);
|
||||
free(p.payload);
|
||||
}
|
||||
is_suspended = false;
|
||||
suspended = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void write_pdu_s(uint8_t* payload, uint32_t nof_bytes)
|
||||
{
|
||||
if (is_suspended) {
|
||||
if (suspended) {
|
||||
queue_pdu(payload, nof_bytes);
|
||||
} else {
|
||||
write_pdu(payload, nof_bytes);
|
||||
|
@ -265,12 +265,13 @@ public:
|
|||
|
||||
// MAC interface
|
||||
virtual bool has_data() = 0;
|
||||
bool is_suspended() { return suspended; };
|
||||
virtual uint32_t get_buffer_state() = 0;
|
||||
virtual int read_pdu(uint8_t* payload, uint32_t nof_bytes) = 0;
|
||||
virtual void write_pdu(uint8_t* payload, uint32_t nof_bytes) = 0;
|
||||
|
||||
private:
|
||||
bool is_suspended = false;
|
||||
bool suspended = false;
|
||||
|
||||
// Enqueues the PDU in the resume queue
|
||||
void queue_pdu(uint8_t* payload, uint32_t nof_bytes)
|
||||
|
|
|
@ -260,6 +260,18 @@ bool rlc::has_data(uint32_t lcid)
|
|||
|
||||
return has_data;
|
||||
}
|
||||
bool rlc::is_suspended(const uint32_t lcid)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
pthread_rwlock_rdlock(&rwlock);
|
||||
if (valid_lcid(lcid)) {
|
||||
ret = rlc_array.at(lcid)->is_suspended();
|
||||
}
|
||||
pthread_rwlock_unlock(&rwlock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t rlc::get_buffer_state(uint32_t lcid)
|
||||
{
|
||||
|
|
|
@ -36,7 +36,7 @@ using namespace asn1::rrc;
|
|||
} \
|
||||
}
|
||||
|
||||
int basic_test()
|
||||
int meas_obj_test()
|
||||
{
|
||||
srslte::log_filter log1("RRC");
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
|
@ -130,6 +130,6 @@ int basic_test()
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
TESTASSERT(basic_test() == 0);
|
||||
TESTASSERT(meas_obj_test() == 0);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
using namespace asn1;
|
||||
using namespace asn1::rrc;
|
||||
|
||||
int basic_test()
|
||||
int meas_obj_test()
|
||||
{
|
||||
srslte::log_filter log1("RRC");
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
|
@ -100,6 +100,6 @@ int basic_test()
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
TESTASSERT(basic_test() == 0);
|
||||
TESTASSERT(meas_obj_test() == 0);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ void basic_test_tx(rlc_am_lte* rlc, byte_buffer_t pdu_bufs[NBUFS])
|
|||
assert(0 == rlc->get_buffer_state());
|
||||
}
|
||||
|
||||
bool basic_test()
|
||||
bool meas_obj_test()
|
||||
{
|
||||
srslte::log_filter log1("RLC_AM_1");
|
||||
srslte::log_filter log2("RLC_AM_2");
|
||||
|
@ -1647,7 +1647,7 @@ bool status_pdu_test()
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (basic_test()) {
|
||||
if (meas_obj_test()) {
|
||||
printf("basic_test failed\n");
|
||||
exit(-1);
|
||||
};
|
||||
|
|
|
@ -71,7 +71,7 @@ public:
|
|||
uint32_t expected_sdu_len;
|
||||
};
|
||||
|
||||
int basic_test()
|
||||
int meas_obj_test()
|
||||
{
|
||||
srslte::log_filter log1("RLC_1");
|
||||
srslte::log_filter log2("RLC_2");
|
||||
|
@ -204,7 +204,7 @@ int basic_test()
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (basic_test()) {
|
||||
if (meas_obj_test()) {
|
||||
return -1;
|
||||
}
|
||||
byte_buffer_pool::get_instance()->cleanup();
|
||||
|
|
|
@ -74,7 +74,7 @@ public:
|
|||
rlc_um_lte rlc1, rlc2;
|
||||
};
|
||||
|
||||
int basic_test()
|
||||
int meas_obj_test()
|
||||
{
|
||||
rlc_um_lte_test_context1 ctxt;
|
||||
|
||||
|
@ -392,7 +392,7 @@ int reassmble_test2()
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (basic_test()) {
|
||||
if (meas_obj_test()) {
|
||||
return -1;
|
||||
}
|
||||
byte_buffer_pool::get_instance()->cleanup();
|
||||
|
|
|
@ -72,9 +72,8 @@ public:
|
|||
cell_search_ret_t cell_search(phy_cell_t* cell) final;
|
||||
bool cell_select(phy_cell_t* cell) final;
|
||||
|
||||
void meas_reset() final;
|
||||
int meas_start(uint32_t earfcn, int pci) final;
|
||||
int meas_stop(uint32_t earfcn, int pci) final;
|
||||
void set_cells_to_meas(uint32_t earfcn, std::set<uint32_t>& pci) final;
|
||||
void meas_stop() final;
|
||||
|
||||
// also MAC interface
|
||||
bool cell_is_camping() final;
|
||||
|
@ -120,10 +119,6 @@ public:
|
|||
|
||||
uint32_t get_current_tti() final;
|
||||
|
||||
void get_current_cell(srslte_cell_t* cell, uint32_t* current_earfcn) final;
|
||||
uint32_t get_current_earfcn() final;
|
||||
uint32_t get_current_pci() final;
|
||||
|
||||
void start_plot() final;
|
||||
|
||||
const static int MAX_WORKERS = 4;
|
||||
|
|
|
@ -63,8 +63,8 @@ public:
|
|||
float cur_pusch_power = 0.0f;
|
||||
float avg_rsrp[SRSLTE_MAX_CARRIERS] = {};
|
||||
float avg_rsrp_dbm[SRSLTE_MAX_CARRIERS] = {};
|
||||
float avg_rsrq_db = 0.0f;
|
||||
float avg_rssi_dbm = 0.0f;
|
||||
float avg_rsrq_db[SRSLTE_MAX_CARRIERS] = {};
|
||||
float avg_rssi_dbm[SRSLTE_MAX_CARRIERS] = {};
|
||||
float rx_gain_offset = 0.0f;
|
||||
float avg_snr_db_cqi[SRSLTE_MAX_CARRIERS] = {};
|
||||
float avg_noise[SRSLTE_MAX_CARRIERS] = {};
|
||||
|
|
|
@ -39,36 +39,33 @@ public:
|
|||
~intra_measure();
|
||||
void init(phy_common* common, rrc_interface_phy_lte* rrc, srslte::log* log_h);
|
||||
void stop();
|
||||
void add_cell(int pci);
|
||||
void rem_cell(int pci);
|
||||
void set_primary_cell(uint32_t earfcn, srslte_cell_t cell);
|
||||
void clear_cells();
|
||||
int get_offset(uint32_t pci);
|
||||
void set_cells_to_meas(std::set<uint32_t>& pci);
|
||||
void meas_stop();
|
||||
void write(uint32_t tti, cf_t* data, uint32_t nsamples);
|
||||
uint32_t get_earfcn() { return current_earfcn; };
|
||||
|
||||
private:
|
||||
void run_thread();
|
||||
const static int INTRA_FREQ_MEAS_PRIO = DEFAULT_PRIORITY + 5;
|
||||
|
||||
scell_recv scell = {};
|
||||
rrc_interface_phy_lte* rrc = nullptr;
|
||||
srslte::log* log_h = nullptr;
|
||||
phy_common* common = nullptr;
|
||||
uint32_t current_earfcn = 0;
|
||||
uint32_t current_sflen = 0;
|
||||
srslte_cell_t primary_cell = {};
|
||||
std::vector<int> active_pci;
|
||||
scell_recv scell = {};
|
||||
rrc_interface_phy_lte* rrc = nullptr;
|
||||
srslte::log* log_h = nullptr;
|
||||
phy_common* common = nullptr;
|
||||
uint32_t current_earfcn = 0;
|
||||
uint32_t current_sflen = 0;
|
||||
srslte_cell_t serving_cell = {};
|
||||
std::set<uint32_t> active_pci = {};
|
||||
std::mutex active_pci_mutex = {};
|
||||
|
||||
srslte::tti_sync_cv tti_sync;
|
||||
|
||||
cf_t* search_buffer = nullptr;
|
||||
|
||||
scell_recv::cell_info_t info[scell_recv::MAX_CELLS] = {};
|
||||
|
||||
bool running = false;
|
||||
bool receive_enabled = false;
|
||||
bool receiving = false;
|
||||
uint32_t measure_tti = 0;
|
||||
uint32_t receive_cnt = 0;
|
||||
srslte_ringbuffer_t ring_buffer = {};
|
||||
|
||||
|
|
|
@ -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
|
|
@ -22,10 +22,10 @@
|
|||
#ifndef SRSUE_SCELL_RECV_H
|
||||
#define SRSUE_SCELL_RECV_H
|
||||
|
||||
#include "srsue/hdr/phy/phy_common.h"
|
||||
#include <set>
|
||||
#include <srslte/srslte.h>
|
||||
|
||||
#include "measure.h"
|
||||
|
||||
namespace srsue {
|
||||
namespace scell {
|
||||
|
||||
|
@ -33,21 +33,10 @@ namespace scell {
|
|||
class scell_recv
|
||||
{
|
||||
public:
|
||||
const static int MAX_CELLS = 8;
|
||||
typedef struct {
|
||||
uint32_t pci;
|
||||
float rsrp;
|
||||
float rsrq;
|
||||
uint32_t offset;
|
||||
} cell_info_t;
|
||||
void init(srslte::log* log_h, bool sic_pss_enabled, uint32_t max_sf_window, phy_common* worker_com);
|
||||
void init(srslte::log* log_h, uint32_t max_sf_window);
|
||||
void deinit();
|
||||
void reset();
|
||||
int find_cells(cf_t* input_buffer,
|
||||
float rx_gain_offset,
|
||||
srslte_cell_t current_cell,
|
||||
uint32_t nof_sf,
|
||||
cell_info_t found_cells[MAX_CELLS]);
|
||||
std::set<uint32_t> find_cells(const cf_t* input_buffer, const srslte_cell_t serving_cell, const uint32_t nof_sf);
|
||||
|
||||
private:
|
||||
// 36.133 9.1.2.1 for band 7
|
||||
|
@ -57,9 +46,7 @@ private:
|
|||
srslte::log* log_h;
|
||||
srslte_sync_t sync_find;
|
||||
|
||||
bool sic_pss_enabled;
|
||||
uint32_t current_fft_sz;
|
||||
measure measure_p;
|
||||
};
|
||||
|
||||
} // namespace scell
|
||||
|
|
|
@ -70,9 +70,9 @@ public:
|
|||
bool cell_is_camping();
|
||||
|
||||
// RRC interface for controlling the neighbour cell measurement
|
||||
void meas_reset();
|
||||
int meas_start(uint32_t earfcn, int pci);
|
||||
int meas_stop(uint32_t earfcn, int pci);
|
||||
void set_cells_to_meas(uint32_t earfcn, std::set<uint32_t>& pci);
|
||||
void set_inter_frequency_measurement(uint32_t cc_idx, uint32_t earfcn_, srslte_cell_t cell_);
|
||||
void meas_stop();
|
||||
|
||||
// from chest_feedback_itf
|
||||
void in_sync() final;
|
||||
|
@ -172,7 +172,7 @@ private:
|
|||
// Objects for internal use
|
||||
search search_p;
|
||||
sfn_sync sfn_p;
|
||||
scell::intra_measure intra_freq_meas;
|
||||
std::vector<std::unique_ptr<scell::intra_measure> > intra_freq_meas;
|
||||
|
||||
uint32_t current_sflen = 0;
|
||||
int next_offset = 0; // Sample offset triggered by Time aligment commands
|
||||
|
|
|
@ -41,7 +41,6 @@ public:
|
|||
|
||||
bool init(srslte::log* log_h,
|
||||
mac_interface_rrc::ue_rnti_t* rntis,
|
||||
srslte::timer_handler::unique_timer* timer_aligment_timer,
|
||||
demux* demux_unit);
|
||||
void reset();
|
||||
void start_pcap(srslte::mac_pcap* pcap_);
|
||||
|
@ -121,7 +120,6 @@ private:
|
|||
|
||||
std::vector<dl_harq_process> proc;
|
||||
dl_harq_process bcch_proc;
|
||||
srslte::timer_handler::unique_timer* timer_aligment_timer = nullptr;
|
||||
demux* demux_unit;
|
||||
srslte::log* log_h;
|
||||
srslte::mac_pcap* pcap;
|
||||
|
|
|
@ -68,9 +68,9 @@ namespace srsue {
|
|||
class cell_t
|
||||
{
|
||||
public:
|
||||
bool is_valid() { return phy_cell.earfcn != 0 && srslte_cell_isvalid(&phy_cell.cell); }
|
||||
bool equals(cell_t* x) { return equals(x->phy_cell.earfcn, x->phy_cell.cell.id); }
|
||||
bool equals(uint32_t earfcn, uint32_t pci) { return earfcn == phy_cell.earfcn && pci == phy_cell.cell.id; }
|
||||
bool is_valid() { return phy_cell.earfcn != 0 && srslte_cellid_isvalid(phy_cell.pci); }
|
||||
bool equals(cell_t* x) { return equals(x->phy_cell.earfcn, x->phy_cell.pci); }
|
||||
bool equals(uint32_t earfcn, uint32_t pci) { return earfcn == phy_cell.earfcn && pci == phy_cell.pci; }
|
||||
// NaN means an RSRP value has not yet been obtained. Keep then in the list and clean them if never updated
|
||||
bool greater(cell_t* x) { return rsrp > x->rsrp || std::isnan(rsrp); }
|
||||
bool plmn_equals(asn1::rrc::plmn_id_s plmn_id)
|
||||
|
@ -113,29 +113,27 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
cell_t()
|
||||
{
|
||||
phy_interface_rrc_lte::phy_cell_t tmp = {};
|
||||
cell_t(tmp, 0);
|
||||
}
|
||||
cell_t(phy_interface_rrc_lte::phy_cell_t phy_cell, float rsrp_)
|
||||
cell_t() { cell_t({0, 0}); }
|
||||
|
||||
cell_t(phy_interface_rrc_lte::phy_cell_t phy_cell_)
|
||||
{
|
||||
gettimeofday(&last_update, nullptr);
|
||||
this->has_valid_sib1 = false;
|
||||
this->has_valid_sib2 = false;
|
||||
this->has_valid_sib3 = false;
|
||||
this->has_valid_sib13 = false;
|
||||
this->phy_cell = phy_cell;
|
||||
rsrp = rsrp_;
|
||||
bzero(&sib1, sizeof(sib1));
|
||||
bzero(&sib2, sizeof(sib2));
|
||||
bzero(&sib3, sizeof(sib3));
|
||||
bzero(&sib13, sizeof(sib13));
|
||||
has_valid_sib1 = false;
|
||||
has_valid_sib2 = false;
|
||||
has_valid_sib3 = false;
|
||||
has_valid_sib13 = false;
|
||||
phy_cell = phy_cell_;
|
||||
rsrp = NAN;
|
||||
rsrq = NAN;
|
||||
sib1 = {};
|
||||
sib2 = {};
|
||||
sib3 = {};
|
||||
sib13 = {};
|
||||
}
|
||||
|
||||
uint32_t get_earfcn() { return phy_cell.earfcn; }
|
||||
|
||||
uint32_t get_pci() { return phy_cell.cell.id; }
|
||||
uint32_t get_pci() { return phy_cell.pci; }
|
||||
|
||||
void set_rsrp(float rsrp_)
|
||||
{
|
||||
|
@ -144,8 +142,15 @@ public:
|
|||
}
|
||||
gettimeofday(&last_update, nullptr);
|
||||
}
|
||||
void set_rsrq(float rsrq_)
|
||||
{
|
||||
if (!std::isnan(rsrq_)) {
|
||||
rsrq = rsrq_;
|
||||
}
|
||||
}
|
||||
|
||||
float get_rsrp() { return rsrp; }
|
||||
float get_rsrq() { return rsrq; }
|
||||
|
||||
void set_sib1(asn1::rrc::sib_type1_s* sib1_)
|
||||
{
|
||||
|
@ -244,7 +249,13 @@ public:
|
|||
std::string print()
|
||||
{
|
||||
char buf[256];
|
||||
snprintf(buf, 256, "{cell_id: 0x%x, pci: %d, dl_earfcn: %d}\n", get_cell_id(), get_pci(), get_earfcn());
|
||||
snprintf(buf,
|
||||
256,
|
||||
"{cell_id: 0x%x, pci: %d, dl_earfcn: %d, rsrp=%+.1f}",
|
||||
get_cell_id(),
|
||||
get_pci(),
|
||||
get_earfcn(),
|
||||
get_rsrp());
|
||||
return std::string{buf};
|
||||
}
|
||||
|
||||
|
@ -258,6 +269,7 @@ public:
|
|||
|
||||
private:
|
||||
float rsrp = NAN;
|
||||
float rsrq = NAN;
|
||||
|
||||
struct timeval last_update = {};
|
||||
|
||||
|
@ -322,7 +334,7 @@ public:
|
|||
// PHY interface
|
||||
void in_sync() final;
|
||||
void out_of_sync() final;
|
||||
void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn, int pci) final;
|
||||
void new_cell_meas(std::vector<phy_meas_t>& meas);
|
||||
|
||||
// MAC interface
|
||||
void ho_ra_completed(bool ra_successful);
|
||||
|
@ -345,9 +357,14 @@ public:
|
|||
void cell_search_completed(const phy_interface_rrc_lte::cell_search_ret_t& cs_ret,
|
||||
const phy_interface_rrc_lte::phy_cell_t& found_cell);
|
||||
|
||||
protected:
|
||||
// Moved to protected to be accessible by unit tests
|
||||
void set_serving_cell(phy_interface_rrc_lte::phy_cell_t phy_cell, bool discard_serving);
|
||||
bool has_neighbour_cell(const uint32_t earfcn, const uint32_t pci);
|
||||
|
||||
private:
|
||||
typedef struct {
|
||||
enum { PDU, PCCH, PDU_MCH, RLF, PDU_BCCH_DLSCH, STOP } command;
|
||||
enum { PDU, PCCH, PDU_MCH, RLF, PDU_BCCH_DLSCH, HO_COMPLETE, STOP } command;
|
||||
srslte::unique_byte_buffer_t pdu;
|
||||
uint16_t lcid;
|
||||
} cmd_msg_t;
|
||||
|
@ -448,19 +465,18 @@ private:
|
|||
std::vector<unique_cell_t> neighbour_cells;
|
||||
unique_cell_t serving_cell = nullptr;
|
||||
void set_serving_cell(uint32_t cell_idx);
|
||||
void set_serving_cell(phy_interface_rrc_lte::phy_cell_t phy_cell);
|
||||
|
||||
unique_cell_t remove_neighbour_cell(const uint32_t earfcn, const uint32_t pci);
|
||||
cell_t* get_neighbour_cell_handle(const uint32_t earfcn, const uint32_t pci);
|
||||
bool has_neighbour_cell(const uint32_t earfcn, const uint32_t pci);
|
||||
int find_neighbour_cell(uint32_t earfcn, uint32_t pci);
|
||||
bool add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp);
|
||||
bool add_neighbour_cell(phy_interface_rrc_lte::phy_cell_t phy_cell, float rsrp);
|
||||
bool add_neighbour_cell(phy_meas_t meas);
|
||||
bool add_neighbour_cell(unique_cell_t new_cell);
|
||||
void log_neighbour_cells();
|
||||
void sort_neighbour_cells();
|
||||
void clean_neighbours();
|
||||
void delete_last_neighbour();
|
||||
std::string print_neighbour_cells();
|
||||
std::set<uint32_t> get_neighbour_pcis(uint32_t earfcn);
|
||||
|
||||
bool initiated = false;
|
||||
asn1::rrc::reest_cause_e m_reest_cause = asn1::rrc::reest_cause_e::nulltype;
|
||||
|
@ -469,117 +485,23 @@ private:
|
|||
bool reestablishment_started = false;
|
||||
bool reestablishment_successful = false;
|
||||
|
||||
// Measurements sub-class
|
||||
class rrc_meas
|
||||
{
|
||||
public:
|
||||
void init(rrc* parent);
|
||||
void reset();
|
||||
bool parse_meas_config(asn1::rrc::meas_cfg_s* meas_config);
|
||||
void new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, float rsrq, uint32_t tti);
|
||||
void run_tti(uint32_t tti);
|
||||
bool timer_expired(uint32_t timer_id);
|
||||
void ho_finish();
|
||||
void delete_report(uint32_t earfcn, uint32_t pci);
|
||||
// Process HO completition in the background
|
||||
void process_ho_ra_completed(bool ra_successful);
|
||||
|
||||
private:
|
||||
const static int NOF_MEASUREMENTS = 3;
|
||||
// Measurements private subclass
|
||||
class rrc_meas;
|
||||
rrc_meas* measurements;
|
||||
|
||||
typedef enum { RSRP = 0, RSRQ = 1, BOTH = 2 } quantity_t;
|
||||
// Interface from rrc_meas
|
||||
void send_srb1_msg(const asn1::rrc::ul_dcch_msg_s& msg);
|
||||
std::set<uint32_t> get_cells(const uint32_t earfcn);
|
||||
float get_cell_rsrp(const uint32_t earfcn, const uint32_t pci);
|
||||
float get_cell_rsrq(const uint32_t earfcn, const uint32_t pci);
|
||||
cell_t* get_serving_cell();
|
||||
|
||||
typedef struct {
|
||||
uint32_t pci;
|
||||
float q_offset;
|
||||
} meas_cell_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t earfcn;
|
||||
float q_offset;
|
||||
std::map<uint32_t, meas_cell_t> meas_cells;
|
||||
std::map<uint32_t, meas_cell_t> found_cells;
|
||||
} meas_obj_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t interval;
|
||||
uint32_t max_cell;
|
||||
int32_t amount;
|
||||
quantity_t trigger_quantity;
|
||||
quantity_t report_quantity;
|
||||
asn1::rrc::eutra_event_s event;
|
||||
enum { EVENT, PERIODIC } trigger_type;
|
||||
} report_cfg_t;
|
||||
|
||||
typedef struct {
|
||||
float ms[NOF_MEASUREMENTS];
|
||||
bool triggered;
|
||||
bool timer_enter_triggered;
|
||||
bool timer_exit_triggered;
|
||||
uint32_t enter_tti;
|
||||
uint32_t exit_tti;
|
||||
} meas_value_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t nof_reports_sent;
|
||||
uint32_t report_id;
|
||||
uint32_t object_id;
|
||||
bool triggered;
|
||||
srslte::timer_handler::unique_timer periodic_timer;
|
||||
std::map<uint32_t, meas_value_t> cell_values; // Value for each PCI in this object
|
||||
} meas_t;
|
||||
|
||||
std::map<uint32_t, meas_obj_t> objects;
|
||||
std::map<uint32_t, report_cfg_t> reports_cfg;
|
||||
std::map<uint32_t, meas_t> active;
|
||||
|
||||
rrc* parent = nullptr;
|
||||
srslte::log* log_h = nullptr;
|
||||
phy_interface_rrc_lte* phy = nullptr;
|
||||
srslte::timer_handler* timers = nullptr;
|
||||
|
||||
uint32_t filter_k_rsrp, filter_k_rsrq = 0;
|
||||
float filter_a[NOF_MEASUREMENTS] = {};
|
||||
|
||||
meas_value_t pcell_measurement = {};
|
||||
|
||||
bool s_measure_enabled = false;
|
||||
float s_measure_value = 0.0;
|
||||
|
||||
void stop_reports(meas_t* m);
|
||||
void stop_reports_object(uint32_t object_id);
|
||||
void remove_meas_object(uint32_t object_id);
|
||||
void remove_meas_report(uint32_t report_id);
|
||||
void remove_meas_id(uint32_t measId);
|
||||
void remove_meas_id(std::map<uint32_t, meas_t>::iterator it);
|
||||
void calculate_triggers(uint32_t tti);
|
||||
void update_phy();
|
||||
void L3_filter(meas_value_t* value, float rsrp[NOF_MEASUREMENTS]);
|
||||
bool find_earfcn_cell(uint32_t earfcn, uint32_t pci, meas_obj_t** object, int* cell_idx);
|
||||
float range_to_value(quantity_t quant, uint8_t range);
|
||||
uint8_t value_to_range(quantity_t quant, float value);
|
||||
bool process_event(asn1::rrc::eutra_event_s* event,
|
||||
uint32_t tti,
|
||||
bool enter_condition,
|
||||
bool exit_condition,
|
||||
meas_t* m,
|
||||
meas_value_t* cell);
|
||||
|
||||
void generate_report(uint32_t meas_id);
|
||||
};
|
||||
|
||||
rrc_meas measurements;
|
||||
|
||||
// Measurement object from phy
|
||||
typedef struct {
|
||||
float rsrp;
|
||||
float rsrq;
|
||||
uint32_t tti;
|
||||
uint32_t earfcn;
|
||||
uint32_t pci;
|
||||
} phy_meas_t;
|
||||
|
||||
void process_phy_meas();
|
||||
void process_new_phy_meas(phy_meas_t meas);
|
||||
srslte::block_queue<phy_meas_t> phy_meas_q;
|
||||
void process_cell_meas();
|
||||
void process_new_cell_meas(std::vector<phy_meas_t>& meas);
|
||||
srslte::block_queue<std::vector<phy_meas_t> > cell_meas_q;
|
||||
|
||||
// Cell selection/reselection functions/variables
|
||||
typedef struct {
|
||||
|
|
|
@ -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_
|
|
@ -131,6 +131,7 @@ private:
|
|||
uint32_t neigh_index;
|
||||
srslte::proc_future_t<phy_interface_rrc_lte::cell_search_ret_t> cell_search_fut;
|
||||
srslte::proc_future_t<void> serv_cell_cfg_fut;
|
||||
bool discard_serving = false;
|
||||
};
|
||||
|
||||
class rrc::plmn_search_proc
|
||||
|
@ -211,6 +212,7 @@ public:
|
|||
static const char* name() { return "Go Idle"; }
|
||||
|
||||
private:
|
||||
bool wait = false;
|
||||
rrc* rrc_ptr;
|
||||
static const uint32_t rlc_flush_timeout = 2000;
|
||||
|
||||
|
@ -238,6 +240,7 @@ public:
|
|||
srslte::proc_outcome_t init(asn1::rrc::reest_cause_e cause);
|
||||
srslte::proc_outcome_t step();
|
||||
static const char* name() { return "Connection re-establishment"; }
|
||||
uint32_t get_source_earfcn() const { return reest_source_freq; }
|
||||
|
||||
private:
|
||||
enum class state_t { cell_reselection, cell_configuration } state;
|
||||
|
@ -246,6 +249,7 @@ private:
|
|||
asn1::rrc::reest_cause_e reest_cause = asn1::rrc::reest_cause_e::nulltype;
|
||||
uint16_t reest_rnti = 0;
|
||||
uint16_t reest_source_pci = 0;
|
||||
uint32_t reest_source_freq = 0;
|
||||
|
||||
srslte::proc_outcome_t step_cell_reselection();
|
||||
srslte::proc_outcome_t step_cell_configuration();
|
||||
|
|
|
@ -77,10 +77,7 @@ public:
|
|||
// RRC interface for PHY
|
||||
void in_sync() final;
|
||||
void out_of_sync() final;
|
||||
void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn = -1, int pci = -1)
|
||||
{
|
||||
rrc.new_phy_meas(rsrp, rsrq, tti, earfcn, pci);
|
||||
};
|
||||
void new_cell_meas(std::vector<phy_meas_t>& meas) { rrc.new_cell_meas(meas); }
|
||||
|
||||
// MAC Interface for PHY
|
||||
uint16_t get_dl_sched_rnti(uint32_t tti) { return mac.get_dl_sched_rnti(tti); }
|
||||
|
|
|
@ -302,10 +302,6 @@ static int parse_args(all_args_t* args, int argc, char* argv[])
|
|||
bpo::value<uint32_t>(&args->phy.cfo_loop_pss_conv)->default_value(DEFAULT_PSS_STABLE_TIMEOUT),
|
||||
"After the PSS estimation is below cfo_loop_pss_tol for cfo_loop_pss_timeout times consecutively, RS adjustments are allowed.")
|
||||
|
||||
("phy.sic_pss_enabled",
|
||||
bpo::value<bool>(&args->phy.sic_pss_enabled)->default_value(false),
|
||||
"Applies Successive Interference Cancellation to PSS signals when searching for neighbour cells. Must be disabled if cells have identical channel and timing.")
|
||||
|
||||
("phy.interpolate_subframe_enabled",
|
||||
bpo::value<bool>(&args->phy.interpolate_subframe_enabled)->default_value(false),
|
||||
"Interpolates in the time domain the channel estimates within 1 subframe.")
|
||||
|
|
|
@ -541,10 +541,11 @@ void cc_worker::update_measurements()
|
|||
// Average RSRQ over DEFAULT_MEAS_PERIOD_MS then sent to RRC
|
||||
float rsrq_db = ue_dl.chest_res.rsrq_db;
|
||||
if (std::isnormal(rsrq_db)) {
|
||||
if (!(CURRENT_TTI % phy->pcell_report_period) || !std::isnormal(phy->avg_rsrq_db)) {
|
||||
phy->avg_rsrq_db = rsrq_db;
|
||||
if (!(CURRENT_TTI % phy->pcell_report_period) || !std::isnormal(phy->avg_rsrq_db[cc_idx])) {
|
||||
phy->avg_rsrq_db[cc_idx] = rsrq_db;
|
||||
} else {
|
||||
phy->avg_rsrq_db = SRSLTE_VEC_CMA(rsrq_db, phy->avg_rsrq_db, CURRENT_TTI % phy->pcell_report_period);
|
||||
phy->avg_rsrq_db[cc_idx] =
|
||||
SRSLTE_VEC_CMA(rsrq_db, phy->avg_rsrq_db[cc_idx], CURRENT_TTI % phy->pcell_report_period);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -597,8 +598,8 @@ void cc_worker::update_measurements()
|
|||
// Store metrics
|
||||
dl_metrics.n = phy->avg_noise[cc_idx];
|
||||
dl_metrics.rsrp = phy->avg_rsrp_dbm[cc_idx];
|
||||
dl_metrics.rsrq = phy->avg_rsrq_db;
|
||||
dl_metrics.rssi = phy->avg_rssi_dbm;
|
||||
dl_metrics.rsrq = phy->avg_rsrq_db[cc_idx];
|
||||
dl_metrics.rssi = phy->avg_rssi_dbm[cc_idx];
|
||||
dl_metrics.pathloss = phy->pathloss[cc_idx];
|
||||
dl_metrics.sinr = phy->avg_snr_db_cqi[cc_idx];
|
||||
dl_metrics.sync_err = ue_dl.chest_res.sync_error;
|
||||
|
|
|
@ -253,7 +253,7 @@ void phy::get_metrics(phy_metrics_t* m)
|
|||
{
|
||||
uint32_t dl_earfcn = 0;
|
||||
srslte_cell_t cell = {};
|
||||
get_current_cell(&cell, &dl_earfcn);
|
||||
sfsync.get_current_cell(&cell, &dl_earfcn);
|
||||
m->info[0].pci = cell.id;
|
||||
m->info[0].dl_earfcn = dl_earfcn;
|
||||
|
||||
|
@ -315,19 +315,14 @@ void phy::configure_prach_params()
|
|||
}
|
||||
}
|
||||
|
||||
void phy::meas_reset()
|
||||
void phy::set_cells_to_meas(uint32_t earfcn, std::set<uint32_t>& pci)
|
||||
{
|
||||
sfsync.meas_reset();
|
||||
sfsync.set_cells_to_meas(earfcn, pci);
|
||||
}
|
||||
|
||||
int phy::meas_start(uint32_t earfcn, int pci)
|
||||
void phy::meas_stop()
|
||||
{
|
||||
return sfsync.meas_start(earfcn, pci);
|
||||
}
|
||||
|
||||
int phy::meas_stop(uint32_t earfcn, int pci)
|
||||
{
|
||||
return sfsync.meas_stop(earfcn, pci);
|
||||
sfsync.meas_stop();
|
||||
}
|
||||
|
||||
bool phy::cell_select(phy_cell_t* cell)
|
||||
|
@ -356,25 +351,6 @@ float phy::get_pathloss_db()
|
|||
return common.cur_pathloss;
|
||||
}
|
||||
|
||||
void phy::get_current_cell(srslte_cell_t* cell, uint32_t* current_earfcn)
|
||||
{
|
||||
sfsync.get_current_cell(cell, current_earfcn);
|
||||
}
|
||||
|
||||
uint32_t phy::get_current_pci()
|
||||
{
|
||||
srslte_cell_t cell;
|
||||
sfsync.get_current_cell(&cell);
|
||||
return cell.id;
|
||||
}
|
||||
|
||||
uint32_t phy::get_current_earfcn()
|
||||
{
|
||||
uint32_t earfcn;
|
||||
sfsync.get_current_cell(nullptr, &earfcn);
|
||||
return earfcn;
|
||||
}
|
||||
|
||||
void phy::prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm)
|
||||
{
|
||||
n_ta = 0;
|
||||
|
@ -479,6 +455,11 @@ void phy::set_config(srslte::phy_cfg_t& config_, uint32_t cc_idx, uint32_t earfc
|
|||
workers[i]->set_config(cc_idx, config_);
|
||||
}
|
||||
|
||||
// Set inter-frequency measurement primary cell
|
||||
if (cell_info) {
|
||||
sfsync.set_inter_frequency_measurement(cc_idx, earfcn, *cell_info);
|
||||
}
|
||||
|
||||
if (cc_idx == 0) {
|
||||
prach_cfg = config_.prach_cfg;
|
||||
} else if (cell_info) {
|
||||
|
|
|
@ -667,15 +667,14 @@ void phy_common::reset()
|
|||
cur_pusch_power = 0;
|
||||
sr_last_tx_tti = -1;
|
||||
cur_pusch_power = 0;
|
||||
pcell_report_period = 20;
|
||||
|
||||
ZERO_OBJECT(pathloss);
|
||||
ZERO_OBJECT(avg_snr_db_cqi);
|
||||
ZERO_OBJECT(avg_rsrp);
|
||||
ZERO_OBJECT(avg_rsrp_dbm);
|
||||
ZERO_OBJECT(avg_rsrq_db);
|
||||
ZERO_OBJECT(scell_cfg);
|
||||
avg_rsrq_db = 0;
|
||||
|
||||
pcell_report_period = 20;
|
||||
|
||||
ZERO_OBJECT(pending_dl_ack);
|
||||
ZERO_OBJECT(pending_dl_dai);
|
||||
ZERO_OBJECT(pending_ul_ack);
|
||||
|
|
|
@ -259,8 +259,6 @@ void async_scell_recv::set_ue_sync_opts(srslte_ue_sync_t* q, float cfo)
|
|||
worker_com->args->cfo_loop_pss_tol,
|
||||
worker_com->args->cfo_loop_pss_conv);
|
||||
|
||||
q->strack.pss.chest_on_filter = worker_com->args->sic_pss_enabled;
|
||||
|
||||
// Disable CP based CFO estimation during find
|
||||
if (cfo != 0) {
|
||||
q->cfo_current_value = cfo / 15000;
|
||||
|
|
|
@ -45,18 +45,18 @@ intra_measure::~intra_measure()
|
|||
free(search_buffer);
|
||||
}
|
||||
|
||||
void intra_measure::init(phy_common* common, rrc_interface_phy_lte* rrc, srslte::log* log_h)
|
||||
void intra_measure::init(phy_common* common_, rrc_interface_phy_lte* rrc_, srslte::log* log_h_)
|
||||
{
|
||||
this->rrc = rrc;
|
||||
this->log_h = log_h;
|
||||
this->common = common;
|
||||
this->rrc = rrc_;
|
||||
this->log_h = log_h_;
|
||||
this->common = common_;
|
||||
receive_enabled = false;
|
||||
|
||||
// Initialise Reference signal measurement
|
||||
srslte_refsignal_dl_sync_init(&refsignal_dl_sync);
|
||||
|
||||
// Start scell
|
||||
scell.init(log_h, common->args->sic_pss_enabled, common->args->intra_freq_meas_len_ms, common);
|
||||
scell.init(log_h, common->args->intra_freq_meas_len_ms);
|
||||
|
||||
search_buffer =
|
||||
(cf_t*)srslte_vec_malloc(common->args->intra_freq_meas_len_ms * SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB) * sizeof(cf_t));
|
||||
|
@ -83,52 +83,27 @@ void intra_measure::set_primary_cell(uint32_t earfcn, srslte_cell_t cell)
|
|||
{
|
||||
this->current_earfcn = earfcn;
|
||||
current_sflen = (uint32_t)SRSLTE_SF_LEN_PRB(cell.nof_prb);
|
||||
this->primary_cell = cell;
|
||||
this->serving_cell = cell;
|
||||
}
|
||||
|
||||
void intra_measure::clear_cells()
|
||||
void intra_measure::meas_stop()
|
||||
{
|
||||
active_pci.clear();
|
||||
receive_enabled = false;
|
||||
receiving = false;
|
||||
receive_cnt = 0;
|
||||
srslte_ringbuffer_reset(&ring_buffer);
|
||||
}
|
||||
|
||||
void intra_measure::add_cell(int pci)
|
||||
{
|
||||
if (std::find(active_pci.begin(), active_pci.end(), pci) == active_pci.end()) {
|
||||
active_pci.push_back(pci);
|
||||
receive_enabled = true;
|
||||
Info("INTRA: Starting intra-frequency measurement for pci=%d\n", pci);
|
||||
} else {
|
||||
Debug("INTRA: Requested to start already existing intra-frequency measurement for PCI=%d\n", pci);
|
||||
if (log_h) {
|
||||
log_h->info("INTRA: Disabled neighbour cell search for EARFCN %d\n", get_earfcn());
|
||||
}
|
||||
}
|
||||
|
||||
int intra_measure::get_offset(uint32_t pci)
|
||||
void intra_measure::set_cells_to_meas(std::set<uint32_t>& pci)
|
||||
{
|
||||
for (auto& i : info) {
|
||||
if (i.pci == pci) {
|
||||
return i.offset;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void intra_measure::rem_cell(int pci)
|
||||
{
|
||||
auto newEnd = std::remove(active_pci.begin(), active_pci.end(), pci);
|
||||
|
||||
if (newEnd != active_pci.end()) {
|
||||
active_pci.erase(newEnd, active_pci.end());
|
||||
if (active_pci.empty()) {
|
||||
receive_enabled = false;
|
||||
}
|
||||
Info("INTRA: Stopping intra-frequency measurement for pci=%d. Number of cells: %zu\n", pci, active_pci.size());
|
||||
} else {
|
||||
Warning("INTRA: Requested to stop non-existing intra-frequency measurement for PCI=%d\n", pci);
|
||||
}
|
||||
active_pci_mutex.lock();
|
||||
active_pci = pci;
|
||||
active_pci_mutex.unlock();
|
||||
receive_enabled = true;
|
||||
log_h->info("INTRA: Received list of %lu neighbour cells to measure in EARFCN %d.\n", pci.size(), current_earfcn);
|
||||
}
|
||||
|
||||
void intra_measure::write(uint32_t tti, cf_t* data, uint32_t nsamples)
|
||||
|
@ -137,7 +112,6 @@ void intra_measure::write(uint32_t tti, cf_t* data, uint32_t nsamples)
|
|||
if ((tti % common->args->intra_freq_meas_period_ms) == 0) {
|
||||
receiving = true;
|
||||
receive_cnt = 0;
|
||||
measure_tti = tti;
|
||||
srslte_ringbuffer_reset(&ring_buffer);
|
||||
}
|
||||
if (receiving) {
|
||||
|
@ -157,6 +131,8 @@ void intra_measure::write(uint32_t tti, cf_t* data, uint32_t nsamples)
|
|||
|
||||
void intra_measure::run_thread()
|
||||
{
|
||||
std::set<uint32_t> cells_to_measure = {};
|
||||
|
||||
while (running) {
|
||||
if (running) {
|
||||
tti_sync.wait();
|
||||
|
@ -164,77 +140,62 @@ void intra_measure::run_thread()
|
|||
|
||||
if (running) {
|
||||
|
||||
active_pci_mutex.lock();
|
||||
cells_to_measure = active_pci;
|
||||
active_pci_mutex.unlock();
|
||||
|
||||
// Read data from buffer and find cells in it
|
||||
srslte_ringbuffer_read(
|
||||
&ring_buffer, search_buffer, common->args->intra_freq_meas_len_ms * current_sflen * sizeof(cf_t));
|
||||
int found_cells = scell.find_cells(
|
||||
search_buffer, common->rx_gain_offset, primary_cell, common->args->intra_freq_meas_len_ms, info);
|
||||
|
||||
// Detect new cells using PSS/SSS
|
||||
std::set<uint32_t> detected_cells =
|
||||
scell.find_cells(search_buffer, serving_cell, common->args->intra_freq_meas_len_ms);
|
||||
|
||||
// Add detected cells to the list of cells to measure
|
||||
for (auto& c : detected_cells) {
|
||||
cells_to_measure.insert(c);
|
||||
}
|
||||
|
||||
receiving = false;
|
||||
|
||||
// Look for other cells not found automatically
|
||||
// Using Cell Reference signal synchronization for all known active PCI
|
||||
for (auto q : active_pci) {
|
||||
srslte_cell_t cell = primary_cell;
|
||||
cell.id = q;
|
||||
std::vector<rrc_interface_phy_lte::phy_meas_t> neigbhour_cells = {};
|
||||
|
||||
// Use Cell Reference signal to measure cells in the time domain for all known active PCI
|
||||
for (auto id : cells_to_measure) {
|
||||
// Do not measure serving cell here since it's measured by workers
|
||||
if (id == serving_cell.id) {
|
||||
continue;
|
||||
}
|
||||
srslte_cell_t cell = serving_cell;
|
||||
cell.id = id;
|
||||
|
||||
srslte_refsignal_dl_sync_set_cell(&refsignal_dl_sync, cell);
|
||||
srslte_refsignal_dl_sync_run(
|
||||
&refsignal_dl_sync, search_buffer, common->args->intra_freq_meas_len_ms * current_sflen);
|
||||
|
||||
if (refsignal_dl_sync.found) {
|
||||
Info("INTRA: Found neighbour cell: PCI=%03d, RSRP=%5.1f dBm, RSRQ=%5.1f, peak_idx=%5d, CFO=%+.1fHz\n",
|
||||
cell.id,
|
||||
refsignal_dl_sync.rsrp_dBfs,
|
||||
refsignal_dl_sync.rsrq_dB,
|
||||
rrc_interface_phy_lte::phy_meas_t m = {};
|
||||
m.pci = cell.id;
|
||||
m.earfcn = current_earfcn;
|
||||
m.rsrp = refsignal_dl_sync.rsrp_dBfs - common->rx_gain_offset;
|
||||
m.rsrq = refsignal_dl_sync.rsrq_dB;
|
||||
neigbhour_cells.push_back(m);
|
||||
|
||||
Info("INTRA: Found neighbour cell: EARFCN=%d, PCI=%03d, RSRP=%5.1f dBm, RSRQ=%5.1f, peak_idx=%5d, "
|
||||
"CFO=%+.1fHz\n",
|
||||
m.earfcn,
|
||||
m.pci,
|
||||
m.rsrp,
|
||||
m.rsrq,
|
||||
refsignal_dl_sync.peak_index,
|
||||
refsignal_dl_sync.cfo_Hz);
|
||||
|
||||
bool found = false;
|
||||
float weakest_rsrp_value = +INFINITY;
|
||||
uint32_t weakest_rsrp_index = 0;
|
||||
|
||||
// Try to find PCI in info list
|
||||
for (int i = 0; i < found_cells && !found; i++) {
|
||||
// Finds cell, update
|
||||
if (info[i].pci == cell.id) {
|
||||
info[i].rsrp = refsignal_dl_sync.rsrp_dBfs;
|
||||
info[i].rsrq = refsignal_dl_sync.rsrq_dB;
|
||||
info[i].offset = refsignal_dl_sync.peak_index;
|
||||
found = true;
|
||||
} else if (weakest_rsrp_value > info[i].rsrp) {
|
||||
// Update weakest
|
||||
weakest_rsrp_value = info[i].rsrp;
|
||||
weakest_rsrp_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
// If number of cells exceeds
|
||||
if (found_cells >= scell_recv::MAX_CELLS) {
|
||||
// overwrite weakest cell if stronger
|
||||
if (refsignal_dl_sync.rsrp_dBfs > weakest_rsrp_value) {
|
||||
info[weakest_rsrp_index].pci = cell.id;
|
||||
info[weakest_rsrp_index].rsrp = refsignal_dl_sync.rsrp_dBfs;
|
||||
info[weakest_rsrp_index].rsrq = refsignal_dl_sync.rsrq_dB;
|
||||
info[weakest_rsrp_index].offset = refsignal_dl_sync.peak_index;
|
||||
} else {
|
||||
// Ignore measurement
|
||||
}
|
||||
} else {
|
||||
// Otherwise append cell
|
||||
info[found_cells].pci = cell.id;
|
||||
info[found_cells].rsrp = refsignal_dl_sync.rsrp_dBfs;
|
||||
info[found_cells].rsrq = refsignal_dl_sync.rsrq_dB;
|
||||
info[found_cells].offset = refsignal_dl_sync.peak_index;
|
||||
found_cells++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send measurements to RRC
|
||||
for (int i = 0; i < found_cells; i++) {
|
||||
rrc->new_phy_meas(info[i].rsrp, info[i].rsrq, measure_tti, current_earfcn, info[i].pci);
|
||||
if (neigbhour_cells.size() > 0) {
|
||||
rrc->new_cell_meas(neigbhour_cells);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -21,19 +21,6 @@
|
|||
|
||||
#include "srsue/hdr/phy/scell/scell_recv.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 {
|
||||
|
||||
|
@ -41,10 +28,9 @@ namespace scell {
|
|||
* Secondary cell receiver
|
||||
*/
|
||||
|
||||
void scell_recv::init(srslte::log* _log_h, bool _sic_pss_enabled, uint32_t max_sf_window, phy_common* worker_com)
|
||||
void scell_recv::init(srslte::log* _log_h, uint32_t max_sf_window)
|
||||
{
|
||||
log_h = _log_h;
|
||||
sic_pss_enabled = _sic_pss_enabled;
|
||||
|
||||
// and a separate ue_sync instance
|
||||
|
||||
|
@ -53,14 +39,13 @@ void scell_recv::init(srslte::log* _log_h, bool _sic_pss_enabled, uint32_t max_s
|
|||
|
||||
sf_buffer[0] = (cf_t*)srslte_vec_malloc(sizeof(cf_t) * max_sf_size);
|
||||
if (!sf_buffer[0]) {
|
||||
ERROR("Error allocating %d samples for scell\n", max_sf_size);
|
||||
log_h->error("Error allocating %d samples for scell\n", max_sf_size);
|
||||
return;
|
||||
}
|
||||
measure_p.init(sf_buffer, log_h, 1, worker_com, max_sf_window);
|
||||
|
||||
// do this different we don't need all this search window.
|
||||
if (srslte_sync_init(&sync_find, max_sf_window * max_sf_size, 5 * max_sf_size, max_fft_sz)) {
|
||||
ERROR("Error initiating sync_find\n");
|
||||
log_h->error("Error initiating sync_find\n");
|
||||
return;
|
||||
}
|
||||
srslte_sync_set_sss_algorithm(&sync_find, SSS_FULL);
|
||||
|
@ -92,179 +77,86 @@ void scell_recv::deinit()
|
|||
void scell_recv::reset()
|
||||
{
|
||||
current_fft_sz = 0;
|
||||
measure_p.reset();
|
||||
}
|
||||
|
||||
int scell_recv::find_cells(cf_t* input_buffer,
|
||||
float rx_gain_offset,
|
||||
srslte_cell_t cell,
|
||||
uint32_t nof_sf,
|
||||
cell_info_t cells[MAX_CELLS])
|
||||
std::set<uint32_t>
|
||||
scell_recv::find_cells(const cf_t* input_buffer, const srslte_cell_t serving_cell, const uint32_t nof_sf)
|
||||
{
|
||||
uint32_t fft_sz = srslte_symbol_sz(cell.nof_prb);
|
||||
std::set<uint32_t> found_cell_ids = {};
|
||||
|
||||
uint32_t fft_sz = srslte_symbol_sz(serving_cell.nof_prb);
|
||||
uint32_t sf_len = SRSLTE_SF_LEN(fft_sz);
|
||||
|
||||
if (fft_sz != current_fft_sz) {
|
||||
if (srslte_sync_resize(&sync_find, nof_sf * sf_len, 5 * sf_len, fft_sz)) {
|
||||
ERROR("Error resizing sync nof_sf=%d, sf_len=%d, fft_sz=%d\n", nof_sf, sf_len, fft_sz);
|
||||
return SRSLTE_ERROR;
|
||||
log_h->error("Error resizing sync nof_sf=%d, sf_len=%d, fft_sz=%d\n", nof_sf, sf_len, fft_sz);
|
||||
return found_cell_ids;
|
||||
}
|
||||
current_fft_sz = fft_sz;
|
||||
}
|
||||
|
||||
int nof_cells = 0;
|
||||
uint32_t peak_idx = 0;
|
||||
uint32_t sf_idx = 0;
|
||||
int cell_id = 0;
|
||||
|
||||
srslte_cell_t found_cell;
|
||||
found_cell = cell;
|
||||
|
||||
measure_p.set_rx_gain_offset(rx_gain_offset);
|
||||
|
||||
for (uint32_t n_id_2 = 0; n_id_2 < 3; n_id_2++) {
|
||||
|
||||
found_cell.id = 10000;
|
||||
|
||||
if (n_id_2 != (cell.id % 3) || sic_pss_enabled) {
|
||||
if (n_id_2 != (serving_cell.id % 3)) {
|
||||
srslte_sync_set_N_id_2(&sync_find, n_id_2);
|
||||
|
||||
srslte_sync_find_ret_t sync_res;
|
||||
|
||||
do {
|
||||
srslte_sync_reset(&sync_find);
|
||||
srslte_sync_cfo_reset(&sync_find);
|
||||
srslte_sync_reset(&sync_find);
|
||||
srslte_sync_cfo_reset(&sync_find);
|
||||
|
||||
sync_res = SRSLTE_SYNC_NOFOUND;
|
||||
bool sss_detected = false;
|
||||
cell_id = 0;
|
||||
float max_peak = -1;
|
||||
uint32_t max_sf5 = 0;
|
||||
uint32_t max_sf_idx = 0;
|
||||
sync_res = SRSLTE_SYNC_NOFOUND;
|
||||
bool sss_detected = false;
|
||||
cell_id = 0;
|
||||
float max_peak = -1;
|
||||
|
||||
float sss_correlation_peak_max = 0.0f;
|
||||
float sss_correlation_peak_max = 0.0f;
|
||||
|
||||
for (uint32_t sf5_cnt = 0; sf5_cnt < nof_sf / 5; sf5_cnt++) {
|
||||
sync_res = srslte_sync_find(&sync_find, input_buffer, sf5_cnt * 5 * sf_len, &peak_idx);
|
||||
Debug("INTRA: n_id_2=%d, cnt=%d/%d, sync_res=%d, sf_idx=%d, peak_idx=%d, peak_value=%f, sss_detected=%d\n",
|
||||
n_id_2,
|
||||
sf5_cnt,
|
||||
nof_sf / 5,
|
||||
sync_res,
|
||||
srslte_sync_get_sf_idx(&sync_find),
|
||||
peak_idx,
|
||||
sync_find.peak_value,
|
||||
srslte_sync_sss_detected(&sync_find));
|
||||
for (uint32_t sf5_cnt = 0; sf5_cnt < nof_sf / 5; sf5_cnt++) {
|
||||
sync_res = srslte_sync_find(&sync_find, input_buffer, sf5_cnt * 5 * sf_len, &peak_idx);
|
||||
if (sync_res == SRSLTE_SYNC_ERROR) {
|
||||
log_h->error("INTRA: Error calling sync_find()\n");
|
||||
return found_cell_ids;
|
||||
}
|
||||
|
||||
if (sync_find.peak_value > max_peak && sync_res == SRSLTE_SYNC_FOUND &&
|
||||
srslte_sync_sss_detected(&sync_find)) {
|
||||
max_sf5 = sf5_cnt;
|
||||
max_sf_idx = srslte_sync_get_sf_idx(&sync_find);
|
||||
if (sync_find.peak_value > max_peak && sync_res == SRSLTE_SYNC_FOUND && srslte_sync_sss_detected(&sync_find)) {
|
||||
|
||||
// Uses the cell ID from the highest SSS correlation peak
|
||||
if (sss_correlation_peak_max < srslte_sync_sss_correlation_peak(&sync_find)) {
|
||||
// Set the cell ID
|
||||
cell_id = srslte_sync_get_cell_id(&sync_find);
|
||||
// Uses the cell ID from the highest SSS correlation peak
|
||||
if (sss_correlation_peak_max < srslte_sync_sss_correlation_peak(&sync_find)) {
|
||||
// Set the cell ID
|
||||
cell_id = srslte_sync_get_cell_id(&sync_find);
|
||||
|
||||
// Update the maximum value
|
||||
sss_correlation_peak_max = srslte_sync_sss_correlation_peak(&sync_find);
|
||||
}
|
||||
sss_detected = true;
|
||||
// Update the maximum value
|
||||
sss_correlation_peak_max = srslte_sync_sss_correlation_peak(&sync_find);
|
||||
}
|
||||
sss_detected = true;
|
||||
}
|
||||
|
||||
// If the SSS was not detected, the cell id is not reliable. So, consider no sync found
|
||||
if (!sss_detected) {
|
||||
sync_res = SRSLTE_SYNC_NOFOUND;
|
||||
}
|
||||
log_h->debug("INTRA: n_id_2=%d, cnt=%d/%d, sync_res=%d, cell_id=%d, sf_idx=%d, peak_idx=%d, peak_value=%f, "
|
||||
"sss_detected=%d\n",
|
||||
n_id_2,
|
||||
sf5_cnt,
|
||||
nof_sf / 5,
|
||||
sync_res,
|
||||
cell_id,
|
||||
srslte_sync_get_sf_idx(&sync_find),
|
||||
peak_idx,
|
||||
sync_find.peak_value,
|
||||
srslte_sync_sss_detected(&sync_find));
|
||||
}
|
||||
|
||||
switch (sync_res) {
|
||||
case SRSLTE_SYNC_ERROR:
|
||||
return SRSLTE_ERROR;
|
||||
ERROR("Error finding correlation peak\n");
|
||||
return SRSLTE_ERROR;
|
||||
case SRSLTE_SYNC_FOUND:
|
||||
|
||||
sf_idx = (10 - max_sf_idx - 5 * (max_sf5 % 2)) % 10;
|
||||
|
||||
if (cell_id >= 0) {
|
||||
// We found the same cell as before, look another N_id_2
|
||||
if ((uint32_t)cell_id == found_cell.id || (uint32_t)cell_id == cell.id) {
|
||||
Debug("INTRA: n_id_2=%d, PCI=%d, found_cell.id=%d, cell.id=%d\n",
|
||||
n_id_2,
|
||||
cell_id,
|
||||
found_cell.id,
|
||||
cell.id);
|
||||
sync_res = SRSLTE_SYNC_NOFOUND;
|
||||
} else {
|
||||
// We found a new cell ID
|
||||
found_cell.id = (uint32_t)cell_id;
|
||||
found_cell.nof_ports = 1; // Use port 0 only for measurement
|
||||
measure_p.set_cell(found_cell);
|
||||
|
||||
// Correct CFO
|
||||
/*
|
||||
srslte_cfo_correct(&sync_find.cfo_corr_frame,
|
||||
input_buffer,
|
||||
input_cfo_corrected,
|
||||
-srslte_sync_get_cfo(&sync_find)/sync_find.fft_size);
|
||||
*/
|
||||
|
||||
switch (measure_p.run_multiple_subframes(input_buffer, peak_idx, sf_idx, nof_sf)) {
|
||||
default:
|
||||
// Consider a cell to be detectable 8.1.2.2.1.1 from 36.133. Currently only using first condition
|
||||
if (measure_p.rsrp() > ABSOLUTE_RSRP_THRESHOLD_DBM) {
|
||||
cells[nof_cells].pci = found_cell.id;
|
||||
cells[nof_cells].rsrp = measure_p.rsrp();
|
||||
cells[nof_cells].rsrq = measure_p.rsrq();
|
||||
cells[nof_cells].offset = measure_p.frame_st_idx();
|
||||
|
||||
Info("INTRA: Found neighbour cell %d: PCI=%03d, RSRP=%5.1f dBm, SNR=%5.1f dB, peak_idx=%5d, "
|
||||
"peak_value=%3.2f, "
|
||||
"sf=%d, max_sf=%d, n_id_2=%d, CFO=%6.1f/%6.1fHz\n",
|
||||
nof_cells,
|
||||
cell_id,
|
||||
measure_p.rsrp(),
|
||||
measure_p.snr(),
|
||||
measure_p.frame_st_idx(),
|
||||
sync_find.peak_value,
|
||||
sf_idx,
|
||||
max_sf5,
|
||||
n_id_2,
|
||||
15000 * srslte_sync_get_cfo(&sync_find),
|
||||
15000 * measure_p.cfo());
|
||||
|
||||
nof_cells++;
|
||||
|
||||
/*
|
||||
if (sic_pss_enabled) {
|
||||
srslte_pss_sic(&sync_find.pss, &input_buffer[sf5_cnt * 5 * sf_len + sf_len / 2 - fft_sz]);
|
||||
}*/
|
||||
} else {
|
||||
Info("INTRA: Found neighbour cell but RSRP=%.1f dBm is below threshold (%.1f dBm)\n",
|
||||
measure_p.rsrp(),
|
||||
ABSOLUTE_RSRP_THRESHOLD_DBM);
|
||||
}
|
||||
break;
|
||||
case measure::ERROR:
|
||||
Error("INTRA: Measuring neighbour cell\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sync_res = SRSLTE_SYNC_NOFOUND;
|
||||
}
|
||||
break;
|
||||
case SRSLTE_SYNC_FOUND_NOSPACE:
|
||||
/* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (sync_res == SRSLTE_SYNC_FOUND && sic_pss_enabled && nof_cells < MAX_CELLS);
|
||||
// If the SSS was not detected, the serving_cell id is not reliable. So, consider no sync found
|
||||
if (sync_res == SRSLTE_SYNC_FOUND && sss_detected && cell_id >= 0) {
|
||||
// We have found a new cell, add to the list
|
||||
found_cell_ids.insert((uint32_t)cell_id);
|
||||
log_h->debug("INTRA: Detected new cell_id=%d using PSS/SSS\n", cell_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return nof_cells;
|
||||
return found_cell_ids;
|
||||
}
|
||||
|
||||
} // namespace scell
|
||||
|
|
|
@ -297,7 +297,7 @@ void sf_worker::update_measurements()
|
|||
30)
|
||||
: 0;
|
||||
if (std::isnormal(rssi_dbm)) {
|
||||
phy->avg_rssi_dbm = SRSLTE_VEC_EMA(rssi_dbm, phy->avg_rssi_dbm, phy->args->snr_ema_coeff);
|
||||
phy->avg_rssi_dbm[0] = SRSLTE_VEC_EMA(rssi_dbm, phy->avg_rssi_dbm[0], phy->args->snr_ema_coeff);
|
||||
}
|
||||
|
||||
if (!rssi_read_cnt) {
|
||||
|
@ -310,27 +310,30 @@ void sf_worker::update_measurements()
|
|||
}
|
||||
|
||||
// Run measurements in all carriers
|
||||
std::vector<rrc_interface_phy_lte::phy_meas_t> serving_cells = {};
|
||||
for (uint32_t cc_idx = 0; cc_idx < cc_workers.size(); cc_idx++) {
|
||||
bool active = (cc_idx == 0 || phy->scell_cfg[cc_idx].configured);
|
||||
|
||||
// Update measurement of the Component Carrier
|
||||
cc_workers[cc_idx]->update_measurements();
|
||||
|
||||
// Send measurements
|
||||
if ((tti % phy->pcell_report_period) == phy->pcell_report_period - 1) {
|
||||
if (cc_idx == 0) {
|
||||
// Send report for PCell
|
||||
phy->stack->new_phy_meas(phy->avg_rsrp_dbm[0], phy->avg_rsrq_db, tti);
|
||||
} else {
|
||||
// Send report for SCell (if enabled)
|
||||
if (phy->scell_cfg[cc_idx].enabled) {
|
||||
phy->stack->new_phy_meas(phy->avg_rsrp_dbm[cc_idx],
|
||||
phy->avg_rsrq_db,
|
||||
tti,
|
||||
phy->scell_cfg[cc_idx].earfcn,
|
||||
phy->scell_cfg[cc_idx].pci);
|
||||
}
|
||||
// Send measurements for serving cells
|
||||
if (active && ((tti % phy->pcell_report_period) == phy->pcell_report_period - 1)) {
|
||||
rrc_interface_phy_lte::phy_meas_t meas = {};
|
||||
meas.rsrp = phy->avg_rsrp_dbm[cc_idx];
|
||||
meas.rsrq = phy->avg_rsrq_db[cc_idx];
|
||||
// Save EARFCN and PCI for secondary cells, primary cell has earfcn=0
|
||||
if (cc_idx > 0) {
|
||||
meas.earfcn = phy->scell_cfg[cc_idx].earfcn;
|
||||
meas.pci = phy->scell_cfg[cc_idx].pci;
|
||||
}
|
||||
serving_cells.push_back(meas);
|
||||
}
|
||||
}
|
||||
// Send report to stack
|
||||
if (not serving_cells.empty()) {
|
||||
phy->stack->new_cell_meas(serving_cells);
|
||||
}
|
||||
|
||||
// Check in-sync / out-sync conditions
|
||||
if (phy->avg_rsrp_dbm[0] > phy->args->in_sync_rsrp_dbm_th && phy->avg_snr_db_cqi[0] > phy->args->in_sync_snr_db_th) {
|
||||
|
|
|
@ -98,7 +98,11 @@ void sync::init(srslte::radio_interface_phy* _radio,
|
|||
sfn_p.init(&ue_sync, sf_buffer[0], log_h);
|
||||
|
||||
// Start intra-frequency measurement
|
||||
intra_freq_meas.init(worker_com, stack, log_h);
|
||||
for (uint32_t i = 0; i < worker_com->args->nof_carriers; i++) {
|
||||
auto q = new scell::intra_measure;
|
||||
q->init(worker_com, stack, log_h);
|
||||
intra_freq_meas.push_back(std::unique_ptr<scell::intra_measure>(q));
|
||||
}
|
||||
|
||||
reset();
|
||||
running = true;
|
||||
|
@ -136,7 +140,9 @@ sync::~sync()
|
|||
void sync::stop()
|
||||
{
|
||||
worker_com->semaphore.wait_all();
|
||||
intra_freq_meas.stop();
|
||||
for (auto& q : intra_freq_meas) {
|
||||
q->stop();
|
||||
}
|
||||
running = false;
|
||||
wait_thread_finish();
|
||||
}
|
||||
|
@ -204,6 +210,9 @@ phy_interface_rrc_lte::cell_search_ret_t sync::cell_search(phy_interface_rrc_lte
|
|||
phy_state.go_idle();
|
||||
worker_com->reset();
|
||||
|
||||
// Stop all intra-frequency measurement before changing frequency
|
||||
meas_stop();
|
||||
|
||||
try {
|
||||
if (current_earfcn != (int)earfcn.at(cellsearch_earfcn_index)) {
|
||||
current_earfcn = (int)earfcn[cellsearch_earfcn_index];
|
||||
|
@ -224,7 +233,9 @@ phy_interface_rrc_lte::cell_search_ret_t sync::cell_search(phy_interface_rrc_lte
|
|||
case search::CELL_FOUND:
|
||||
// If a cell is found, configure it, synchronize and measure it
|
||||
if (set_cell()) {
|
||||
intra_freq_meas.set_primary_cell(current_earfcn, cell);
|
||||
|
||||
// Reconfigure first intra-frequency measurement
|
||||
intra_freq_meas[0]->set_primary_cell(current_earfcn, cell);
|
||||
|
||||
Info("Cell Search: Setting sampling rate and synchronizing SFN...\n");
|
||||
set_sampling_rate();
|
||||
|
@ -234,7 +245,7 @@ phy_interface_rrc_lte::cell_search_ret_t sync::cell_search(phy_interface_rrc_lte
|
|||
log_h->info("Cell Search: Sync OK. Camping on cell PCI=%d\n", cell.id);
|
||||
if (found_cell) {
|
||||
found_cell->earfcn = current_earfcn;
|
||||
found_cell->cell = cell;
|
||||
found_cell->pci = cell.id;
|
||||
}
|
||||
ret.found = phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND;
|
||||
} else {
|
||||
|
@ -282,14 +293,11 @@ bool sync::cell_select(phy_interface_rrc_lte::phy_cell_t* new_cell)
|
|||
if (!new_cell) {
|
||||
Info("Cell Select: Starting cell resynchronization\n");
|
||||
} else {
|
||||
if (!srslte_cell_isvalid(&new_cell->cell)) {
|
||||
log_h->error("Cell Select: Invalid cell. ID=%d, PRB=%d, ports=%d\n", cell.id, cell.nof_prb, cell.nof_ports);
|
||||
if (!srslte_cellid_isvalid(new_cell->pci)) {
|
||||
log_h->error("Cell Select: Invalid cell_id=%d\n", cell.id);
|
||||
return ret;
|
||||
}
|
||||
Info("Cell Select: Starting cell selection for PCI=%d, n_prb=%d, EARFCN=%d\n",
|
||||
new_cell->cell.id,
|
||||
new_cell->cell.nof_prb,
|
||||
new_cell->earfcn);
|
||||
Info("Cell Select: Starting cell selection for PCI=%d, EARFCN=%d\n", new_cell->pci, new_cell->earfcn);
|
||||
}
|
||||
|
||||
// Wait for any pending PHICH
|
||||
|
@ -309,9 +317,9 @@ bool sync::cell_select(phy_interface_rrc_lte::phy_cell_t* new_cell)
|
|||
|
||||
/* Reconfigure cell if necessary */
|
||||
if (new_cell) {
|
||||
if (new_cell->cell.id != cell.id) {
|
||||
Info("Cell Select: Reconfiguring cell\n");
|
||||
cell = new_cell->cell;
|
||||
if (new_cell->pci != cell.id) {
|
||||
Info("Cell Select: Reconfiguring cell ID\n");
|
||||
cell.id = new_cell->pci;
|
||||
if (!set_cell()) {
|
||||
Error("Cell Select: Reconfiguring cell\n");
|
||||
return ret;
|
||||
|
@ -321,6 +329,10 @@ bool sync::cell_select(phy_interface_rrc_lte::phy_cell_t* new_cell)
|
|||
/* Select new frequency if necessary */
|
||||
if ((int)new_cell->earfcn != current_earfcn) {
|
||||
current_earfcn = new_cell->earfcn;
|
||||
|
||||
// Stop all intra-frequency measurement before changing frequency
|
||||
meas_stop();
|
||||
|
||||
Info("Cell Select: Setting new frequency EARFCN=%d\n", new_cell->earfcn);
|
||||
if (!set_frequency()) {
|
||||
Error("Cell Select: Setting new frequency EARFCN=%d\n", new_cell->earfcn);
|
||||
|
@ -328,14 +340,14 @@ bool sync::cell_select(phy_interface_rrc_lte::phy_cell_t* new_cell)
|
|||
}
|
||||
}
|
||||
|
||||
/* Reconfigure intra-frequency measurement */
|
||||
intra_freq_meas.set_primary_cell(current_earfcn, cell);
|
||||
// Reconfigure first intra-frequency measurement
|
||||
intra_freq_meas[0]->set_primary_cell(current_earfcn, cell);
|
||||
}
|
||||
|
||||
/* Change sampling rate if necessary */
|
||||
if (srate_mode != SRATE_CAMP) {
|
||||
set_sampling_rate();
|
||||
log_h->info("Cell Select: Setting CAMPING sampling rate\n");
|
||||
set_sampling_rate();
|
||||
}
|
||||
|
||||
/* SFN synchronization */
|
||||
|
@ -375,7 +387,8 @@ bool sync::cell_is_camping()
|
|||
void sync::run_thread()
|
||||
{
|
||||
sf_worker* worker = nullptr;
|
||||
cf_t* buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS] = {NULL};
|
||||
cf_t* buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS] = {};
|
||||
srslte_cell_t temp_cell = {};
|
||||
|
||||
bool is_end_of_burst = false;
|
||||
bool force_camping_sfn_sync = false;
|
||||
|
@ -419,8 +432,18 @@ void sync::run_thread()
|
|||
/* SFN synchronization using MIB. run_subframe() receives and processes 1 subframe
|
||||
* and returns
|
||||
*/
|
||||
switch (sfn_p.run_subframe(&cell, &tti, mib)) {
|
||||
temp_cell = cell;
|
||||
switch (sfn_p.run_subframe(&temp_cell, &tti, mib)) {
|
||||
case sfn_sync::SFN_FOUND:
|
||||
if (memcmp(&cell, &temp_cell, sizeof(srslte_cell_t))) {
|
||||
srslte_cell_fprint(stdout, &cell, 0);
|
||||
srslte_cell_fprint(stdout, &temp_cell, 0);
|
||||
log_h->error("Detected cell during SFN synchronization differs from configured cell. Cell reselection to "
|
||||
"cells with different MIB is not supported\n");
|
||||
log_h->console("Detected cell during SFN synchronization differs from configured cell. Cell reselection "
|
||||
"to cells with different MIB is not supported\n");
|
||||
phy_state.state_exit(false);
|
||||
}
|
||||
stack->in_sync();
|
||||
phy_state.state_exit();
|
||||
break;
|
||||
|
@ -459,16 +482,22 @@ void sync::run_thread()
|
|||
|
||||
// Force decode MIB if required
|
||||
if (force_camping_sfn_sync) {
|
||||
uint32_t _tti = 0;
|
||||
srslte_cell_t temp_cell = {};
|
||||
uint32_t _tti = 0;
|
||||
temp_cell = cell;
|
||||
sync::sfn_sync::ret_code ret = sfn_p.decode_mib(&temp_cell, &_tti, buffer[0], mib);
|
||||
|
||||
if (ret == sfn_sync::SFN_FOUND) {
|
||||
// Force tti
|
||||
tti = _tti;
|
||||
|
||||
// Disable
|
||||
force_camping_sfn_sync = false;
|
||||
|
||||
if (memcmp(&cell, &temp_cell, sizeof(srslte_cell_t))) {
|
||||
log_h->error("Detected cell during SFN synchronization differs from configured cell. Cell "
|
||||
"reselection to cells with different MIB is not supported\n");
|
||||
log_h->console("Detected cell during SFN synchronization differs from configured cell. Cell "
|
||||
"reselection to cells with different MIB is not supported\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -561,12 +590,10 @@ void sync::run_thread()
|
|||
workers_pool->start_worker(worker);
|
||||
|
||||
// Save signal for Intra-frequency measurement
|
||||
if ((tti % 5) == 0 && worker_com->args->sic_pss_enabled) {
|
||||
srslte_pss_sic(&ue_sync.strack.pss,
|
||||
&buffer[0][0][SRSLTE_SF_LEN_PRB(cell.nof_prb) / 2 - ue_sync.strack.fft_size]);
|
||||
}
|
||||
if (srslte_cell_isvalid(&cell)) {
|
||||
intra_freq_meas.write(tti, buffer[0][0], SRSLTE_SF_LEN_PRB(cell.nof_prb));
|
||||
for (size_t i = 0; i < intra_freq_meas.size(); i++) {
|
||||
intra_freq_meas[i]->write(tti, worker->get_buffer(i, 0), SRSLTE_SF_LEN_PRB(cell.nof_prb));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
|
@ -723,12 +750,12 @@ void sync::set_agc_enable(bool enable)
|
|||
}
|
||||
}
|
||||
|
||||
void sync::set_time_adv_sec(float time_adv_sec)
|
||||
void sync::set_time_adv_sec(float time_adv_sec_)
|
||||
{
|
||||
// If transmitting earlier, transmit less samples to align time advance. If transmit later just delay next TX
|
||||
next_offset = (int)round((this->time_adv_sec - time_adv_sec) * srslte_sampling_freq_hz(cell.nof_prb));
|
||||
this->next_time_adv_sec = time_adv_sec;
|
||||
Info("Applying time_adv_sec=%.1f us, next_offset=%d\n", time_adv_sec * 1e6, next_offset);
|
||||
next_offset = (int)round((time_adv_sec - time_adv_sec_) * srslte_sampling_freq_hz(cell.nof_prb));
|
||||
next_time_adv_sec = time_adv_sec_;
|
||||
Info("Applying time_adv_sec=%.1f us, next_offset=%d\n", time_adv_sec_ * 1e6, next_offset);
|
||||
}
|
||||
|
||||
float sync::get_tx_cfo()
|
||||
|
@ -766,8 +793,6 @@ void sync::set_ue_sync_opts(srslte_ue_sync_t* q, float cfo)
|
|||
worker_com->args->cfo_loop_pss_tol,
|
||||
worker_com->args->cfo_loop_pss_conv);
|
||||
|
||||
q->strack.pss.chest_on_filter = worker_com->args->sic_pss_enabled;
|
||||
|
||||
// Disable CP based CFO estimation during find
|
||||
if (cfo != 0) {
|
||||
q->cfo_current_value = cfo / 15000;
|
||||
|
@ -802,6 +827,11 @@ bool sync::set_cell()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!srslte_cell_isvalid(&cell)) {
|
||||
Error("SYNC: Setting cell: invalid cell (nof_prb=%d, pci=%d, ports=%d)\n", cell.nof_prb, cell.id, cell.nof_ports);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set cell in all objects
|
||||
if (srslte_ue_sync_set_cell(&ue_sync, cell)) {
|
||||
Error("SYNC: Setting cell: initiating ue_sync\n");
|
||||
|
@ -826,15 +856,15 @@ bool sync::set_cell()
|
|||
return true;
|
||||
}
|
||||
|
||||
void sync::set_earfcn(std::vector<uint32_t> earfcn)
|
||||
void sync::set_earfcn(std::vector<uint32_t> earfcn_)
|
||||
{
|
||||
this->earfcn = earfcn;
|
||||
earfcn = earfcn_;
|
||||
}
|
||||
|
||||
void sync::force_freq(float dl_freq, float ul_freq)
|
||||
void sync::force_freq(float dl_freq_, float ul_freq_)
|
||||
{
|
||||
this->dl_freq = dl_freq;
|
||||
this->ul_freq = ul_freq;
|
||||
dl_freq = dl_freq_;
|
||||
ul_freq = ul_freq_;
|
||||
}
|
||||
|
||||
bool sync::set_frequency()
|
||||
|
@ -842,9 +872,9 @@ bool sync::set_frequency()
|
|||
double set_dl_freq = 0;
|
||||
double set_ul_freq = 0;
|
||||
|
||||
if (this->dl_freq > 0 && this->ul_freq > 0) {
|
||||
set_dl_freq = this->dl_freq;
|
||||
set_ul_freq = this->ul_freq;
|
||||
if (dl_freq > 0 && ul_freq > 0) {
|
||||
set_dl_freq = dl_freq;
|
||||
set_ul_freq = ul_freq;
|
||||
} else {
|
||||
set_dl_freq = 1e6 * srslte_band_fd(current_earfcn);
|
||||
if (srslte_band_is_tdd(srslte_band_get_band(current_earfcn))) {
|
||||
|
@ -907,13 +937,13 @@ uint32_t sync::get_current_tti()
|
|||
return tti;
|
||||
}
|
||||
|
||||
void sync::get_current_cell(srslte_cell_t* cell, uint32_t* earfcn)
|
||||
void sync::get_current_cell(srslte_cell_t* cell_, uint32_t* earfcn_)
|
||||
{
|
||||
if (cell) {
|
||||
*cell = this->cell;
|
||||
if (cell_) {
|
||||
*cell_ = cell;
|
||||
}
|
||||
if (earfcn) {
|
||||
*earfcn = current_earfcn;
|
||||
if (earfcn_) {
|
||||
*earfcn_ = current_earfcn;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -977,13 +1007,13 @@ sync::search::~search()
|
|||
srslte_ue_cellsearch_free(&cs);
|
||||
}
|
||||
|
||||
void sync::search::init(cf_t* buffer[SRSLTE_MAX_PORTS], srslte::log* log_h, uint32_t nof_rx_antennas, sync* parent)
|
||||
void sync::search::init(cf_t* buffer_[SRSLTE_MAX_PORTS], srslte::log* log_h_, uint32_t nof_rx_antennas, sync* parent)
|
||||
{
|
||||
this->log_h = log_h;
|
||||
this->p = parent;
|
||||
log_h = log_h_;
|
||||
p = parent;
|
||||
|
||||
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
this->buffer[i] = buffer[i];
|
||||
buffer[i] = buffer_[i];
|
||||
}
|
||||
|
||||
if (srslte_ue_cellsearch_init_multi(&cs, 8, radio_recv_callback, nof_rx_antennas, parent)) {
|
||||
|
@ -1025,15 +1055,12 @@ void sync::search::set_agc_enable(bool enable)
|
|||
}
|
||||
}
|
||||
|
||||
sync::search::ret_code sync::search::run(srslte_cell_t* cell, std::array<uint8_t, SRSLTE_BCH_PAYLOAD_LEN>& bch_payload)
|
||||
sync::search::ret_code sync::search::run(srslte_cell_t* cell_, std::array<uint8_t, SRSLTE_BCH_PAYLOAD_LEN>& bch_payload)
|
||||
{
|
||||
if (!cell) {
|
||||
return ERROR;
|
||||
}
|
||||
srslte_cell_t new_cell = {};
|
||||
|
||||
srslte_ue_cellsearch_result_t found_cells[3];
|
||||
|
||||
bzero(cell, sizeof(srslte_cell_t));
|
||||
bzero(found_cells, 3 * sizeof(srslte_ue_cellsearch_result_t));
|
||||
|
||||
if (p->srate_mode != SRATE_FIND) {
|
||||
|
@ -1065,19 +1092,19 @@ sync::search::ret_code sync::search::run(srslte_cell_t* cell, std::array<uint8_t
|
|||
return CELL_NOT_FOUND;
|
||||
}
|
||||
// Save result
|
||||
cell->id = found_cells[max_peak_cell].cell_id;
|
||||
cell->cp = found_cells[max_peak_cell].cp;
|
||||
cell->frame_type = found_cells[max_peak_cell].frame_type;
|
||||
float cfo = found_cells[max_peak_cell].cfo;
|
||||
new_cell.id = found_cells[max_peak_cell].cell_id;
|
||||
new_cell.cp = found_cells[max_peak_cell].cp;
|
||||
new_cell.frame_type = found_cells[max_peak_cell].frame_type;
|
||||
float cfo = found_cells[max_peak_cell].cfo;
|
||||
|
||||
log_h->console("\n");
|
||||
Info("SYNC: PSS/SSS detected: Mode=%s, PCI=%d, CFO=%.1f KHz, CP=%s\n",
|
||||
cell->frame_type ? "TDD" : "FDD",
|
||||
cell->id,
|
||||
new_cell.frame_type ? "TDD" : "FDD",
|
||||
new_cell.id,
|
||||
cfo / 1000,
|
||||
srslte_cp_string(cell->cp));
|
||||
srslte_cp_string(new_cell.cp));
|
||||
|
||||
if (srslte_ue_mib_sync_set_cell(&ue_mib_sync, *cell)) {
|
||||
if (srslte_ue_mib_sync_set_cell(&ue_mib_sync, new_cell)) {
|
||||
Error("SYNC: Setting UE MIB cell\n");
|
||||
return ERROR;
|
||||
}
|
||||
|
@ -1089,9 +1116,9 @@ sync::search::ret_code sync::search::run(srslte_cell_t* cell, std::array<uint8_t
|
|||
|
||||
/* Find and decode MIB */
|
||||
int sfn_offset;
|
||||
ret = srslte_ue_mib_sync_decode(&ue_mib_sync, 40, bch_payload.data(), &cell->nof_ports, &sfn_offset);
|
||||
ret = srslte_ue_mib_sync_decode(&ue_mib_sync, 40, bch_payload.data(), &new_cell.nof_ports, &sfn_offset);
|
||||
if (ret == 1) {
|
||||
srslte_pbch_mib_unpack(bch_payload.data(), cell, NULL);
|
||||
srslte_pbch_mib_unpack(bch_payload.data(), &new_cell, NULL);
|
||||
// pack MIB and store inplace for PCAP dump
|
||||
std::array<uint8_t, SRSLTE_BCH_PAYLOAD_LEN / 8> mib_packed;
|
||||
srslte_bit_pack_vector(bch_payload.data(), mib_packed.data(), SRSLTE_BCH_PAYLOAD_LEN);
|
||||
|
@ -1099,23 +1126,29 @@ sync::search::ret_code sync::search::run(srslte_cell_t* cell, std::array<uint8_t
|
|||
|
||||
fprintf(stdout,
|
||||
"Found Cell: Mode=%s, PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n",
|
||||
cell->frame_type ? "TDD" : "FDD",
|
||||
cell->id,
|
||||
cell->nof_prb,
|
||||
cell->nof_ports,
|
||||
new_cell.frame_type ? "TDD" : "FDD",
|
||||
new_cell.id,
|
||||
new_cell.nof_prb,
|
||||
new_cell.nof_ports,
|
||||
cfo / 1000);
|
||||
|
||||
Info("SYNC: MIB Decoded: Mode=%s, PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n",
|
||||
cell->frame_type ? "TDD" : "FDD",
|
||||
cell->id,
|
||||
cell->nof_prb,
|
||||
cell->nof_ports,
|
||||
new_cell.frame_type ? "TDD" : "FDD",
|
||||
new_cell.id,
|
||||
new_cell.nof_prb,
|
||||
new_cell.nof_ports,
|
||||
cfo / 1000);
|
||||
|
||||
if (!srslte_cell_isvalid(cell)) {
|
||||
if (!srslte_cell_isvalid(&new_cell)) {
|
||||
Error("SYNC: Detected invalid cell.\n");
|
||||
return CELL_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Save cell pointer
|
||||
if (cell_) {
|
||||
*cell_ = new_cell;
|
||||
}
|
||||
|
||||
return CELL_FOUND;
|
||||
} else if (ret == 0) {
|
||||
Warning("SYNC: Found PSS but could not decode PBCH\n");
|
||||
|
@ -1135,27 +1168,27 @@ sync::sfn_sync::~sfn_sync()
|
|||
srslte_ue_mib_free(&ue_mib);
|
||||
}
|
||||
|
||||
void sync::sfn_sync::init(srslte_ue_sync_t* ue_sync,
|
||||
cf_t* buffer[SRSLTE_MAX_PORTS],
|
||||
srslte::log* log_h,
|
||||
void sync::sfn_sync::init(srslte_ue_sync_t* ue_sync_,
|
||||
cf_t* buffer_[SRSLTE_MAX_PORTS],
|
||||
srslte::log* log_h_,
|
||||
uint32_t nof_subframes)
|
||||
{
|
||||
this->log_h = log_h;
|
||||
this->ue_sync = ue_sync;
|
||||
this->timeout = nof_subframes;
|
||||
log_h = log_h_;
|
||||
ue_sync = ue_sync_;
|
||||
timeout = nof_subframes;
|
||||
|
||||
for (int p = 0; p < SRSLTE_MAX_PORTS; p++) {
|
||||
this->buffer[p] = buffer[p];
|
||||
buffer[p] = buffer_[p];
|
||||
}
|
||||
|
||||
if (srslte_ue_mib_init(&ue_mib, this->buffer, SRSLTE_MAX_PRB)) {
|
||||
if (srslte_ue_mib_init(&ue_mib, buffer, SRSLTE_MAX_PRB)) {
|
||||
Error("SYNC: Initiating UE MIB decoder\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool sync::sfn_sync::set_cell(srslte_cell_t cell)
|
||||
bool sync::sfn_sync::set_cell(srslte_cell_t cell_)
|
||||
{
|
||||
if (srslte_ue_mib_set_cell(&ue_mib, cell)) {
|
||||
if (srslte_ue_mib_set_cell(&ue_mib, cell_)) {
|
||||
Error("SYNC: Setting cell: initiating ue_mib\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -1169,7 +1202,7 @@ void sync::sfn_sync::reset()
|
|||
srslte_ue_mib_reset(&ue_mib);
|
||||
}
|
||||
|
||||
sync::sfn_sync::ret_code sync::sfn_sync::run_subframe(srslte_cell_t* cell,
|
||||
sync::sfn_sync::ret_code sync::sfn_sync::run_subframe(srslte_cell_t* cell_,
|
||||
uint32_t* tti_cnt,
|
||||
std::array<uint8_t, SRSLTE_BCH_PAYLOAD_LEN>& bch_payload,
|
||||
bool sfidx_only)
|
||||
|
@ -1182,7 +1215,7 @@ sync::sfn_sync::ret_code sync::sfn_sync::run_subframe(srslte_cell_t*
|
|||
}
|
||||
|
||||
if (ret == 1) {
|
||||
sync::sfn_sync::ret_code ret2 = decode_mib(cell, tti_cnt, NULL, bch_payload, sfidx_only);
|
||||
sync::sfn_sync::ret_code ret2 = decode_mib(cell_, tti_cnt, NULL, bch_payload, sfidx_only);
|
||||
if (ret2 != SFN_NOFOUND) {
|
||||
return ret2;
|
||||
}
|
||||
|
@ -1199,7 +1232,7 @@ sync::sfn_sync::ret_code sync::sfn_sync::run_subframe(srslte_cell_t*
|
|||
return IDLE;
|
||||
}
|
||||
|
||||
sync::sfn_sync::ret_code sync::sfn_sync::decode_mib(srslte_cell_t* cell,
|
||||
sync::sfn_sync::ret_code sync::sfn_sync::decode_mib(srslte_cell_t* cell_,
|
||||
uint32_t* tti_cnt,
|
||||
cf_t* ext_buffer[SRSLTE_MAX_PORTS],
|
||||
std::array<uint8_t, SRSLTE_BCH_PAYLOAD_LEN>& bch_payload,
|
||||
|
@ -1228,7 +1261,7 @@ sync::sfn_sync::ret_code sync::sfn_sync::decode_mib(srslte_cell_t* cell,
|
|||
return ERROR;
|
||||
case SRSLTE_UE_MIB_FOUND:
|
||||
uint32_t sfn;
|
||||
srslte_pbch_mib_unpack(bch_payload.data(), cell, &sfn);
|
||||
srslte_pbch_mib_unpack(bch_payload.data(), cell_, &sfn);
|
||||
|
||||
sfn = (sfn + sfn_offset) % 1024;
|
||||
if (tti_cnt) {
|
||||
|
@ -1252,39 +1285,31 @@ sync::sfn_sync::ret_code sync::sfn_sync::decode_mib(srslte_cell_t* cell,
|
|||
*
|
||||
*/
|
||||
|
||||
void sync::meas_reset()
|
||||
void sync::set_inter_frequency_measurement(uint32_t cc_idx, uint32_t earfcn_, srslte_cell_t cell_)
|
||||
{
|
||||
// Stop all measurements
|
||||
intra_freq_meas.clear_cells();
|
||||
if (cc_idx < intra_freq_meas.size()) {
|
||||
intra_freq_meas[cc_idx]->set_primary_cell(earfcn_, cell_);
|
||||
}
|
||||
}
|
||||
|
||||
int sync::meas_start(uint32_t earfcn, int pci)
|
||||
void sync::set_cells_to_meas(uint32_t earfcn_, std::set<uint32_t>& pci)
|
||||
{
|
||||
if ((int)earfcn == current_earfcn) {
|
||||
if (pci != (int)cell.id) {
|
||||
intra_freq_meas.add_cell(pci);
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < intra_freq_meas.size() and not found; i++) {
|
||||
if (earfcn_ == intra_freq_meas[i]->get_earfcn()) {
|
||||
intra_freq_meas[i]->set_cells_to_meas(pci);
|
||||
found = true;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
Warning("INTRA: Inter-frequency measurements not supported (current EARFCN=%d, requested measurement for %d)\n",
|
||||
current_earfcn,
|
||||
earfcn);
|
||||
return -1;
|
||||
}
|
||||
if (!found) {
|
||||
log_h->error("Neighbour cell measurement not supported in secondary carrier. EARFCN=%d\n", earfcn_);
|
||||
}
|
||||
}
|
||||
|
||||
int sync::meas_stop(uint32_t earfcn, int pci)
|
||||
void sync::meas_stop()
|
||||
{
|
||||
if ((int)earfcn == current_earfcn) {
|
||||
intra_freq_meas.rem_cell(pci);
|
||||
return 0;
|
||||
} else {
|
||||
Warning(
|
||||
"INTRA: Inter-frequency measurements not supported (current EARFCN=%d, requested stop measurement for %d)\n",
|
||||
current_earfcn,
|
||||
earfcn);
|
||||
for (auto& q : intra_freq_meas) {
|
||||
q->meas_stop();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace srsue
|
||||
|
|
|
@ -34,25 +34,20 @@ namespace srsue {
|
|||
|
||||
dl_harq_entity::dl_harq_entity() : proc(SRSLTE_MAX_HARQ_PROC)
|
||||
{
|
||||
pcap = NULL;
|
||||
demux_unit = NULL;
|
||||
log_h = NULL;
|
||||
timer_aligment_timer = NULL;
|
||||
pcap = nullptr;
|
||||
demux_unit = nullptr;
|
||||
log_h = nullptr;
|
||||
si_window_start = 0;
|
||||
last_temporal_crnti = 0;
|
||||
average_retx = 0;
|
||||
nof_pkts = 0;
|
||||
}
|
||||
|
||||
bool dl_harq_entity::init(srslte::log* log_h,
|
||||
mac_interface_rrc::ue_rnti_t* rntis,
|
||||
srslte::timer_handler::unique_timer* timer_aligment_timer_,
|
||||
demux* demux_unit)
|
||||
bool dl_harq_entity::init(srslte::log* log_h_, mac_interface_rrc::ue_rnti_t* rntis_, demux* demux_unit_)
|
||||
{
|
||||
timer_aligment_timer = timer_aligment_timer_;
|
||||
this->demux_unit = demux_unit;
|
||||
this->log_h = log_h;
|
||||
this->rntis = rntis;
|
||||
demux_unit = demux_unit_;
|
||||
log_h = log_h_;
|
||||
rntis = rntis_;
|
||||
|
||||
for (uint32_t i = 0; i < SRSLTE_MAX_HARQ_PROC; i++) {
|
||||
if (!proc[i].init(i, this)) {
|
||||
|
@ -329,12 +324,8 @@ void dl_harq_entity::dl_harq_process::dl_tb_process::new_grant_dl(mac_interface_
|
|||
}
|
||||
}
|
||||
|
||||
if (is_bcch || harq_entity->timer_aligment_timer->is_expired()) {
|
||||
// Do not generate ACK
|
||||
action->generate_ack = false;
|
||||
} else {
|
||||
action->generate_ack = true;
|
||||
}
|
||||
// Do NOT generate ACK if Broadcast Control Channel
|
||||
action->generate_ack = not is_bcch;
|
||||
}
|
||||
|
||||
void dl_harq_entity::dl_harq_process::dl_tb_process::tb_decoded(mac_interface_phy_lte::mac_grant_dl_t grant,
|
||||
|
|
|
@ -90,7 +90,7 @@ bool mac::init(phy_interface_mac_lte* phy,
|
|||
|
||||
// Create UL/DL unique HARQ pointers
|
||||
ul_harq.at(0)->init(log_h, &uernti, &ra_procedure, &mux_unit);
|
||||
dl_harq.at(0)->init(log_h, &uernti, &timer_alignment, &demux_unit);
|
||||
dl_harq.at(0)->init(log_h, &uernti, &demux_unit);
|
||||
|
||||
reset();
|
||||
|
||||
|
@ -137,7 +137,7 @@ void mac::reconfiguration(const uint32_t& cc_idx, const bool& enable)
|
|||
}
|
||||
while (dl_harq.size() < cc_idx + 1) {
|
||||
auto dl = dl_harq_entity_ptr(new dl_harq_entity());
|
||||
dl->init(log_h, &uernti, &timer_alignment, &demux_unit);
|
||||
dl->init(log_h, &uernti, &demux_unit);
|
||||
|
||||
if (pcap) {
|
||||
dl->start_pcap(pcap);
|
||||
|
@ -538,6 +538,7 @@ void mac::setup_timers(int time_alignment_timer)
|
|||
void mac::timer_expired(uint32_t timer_id)
|
||||
{
|
||||
if (timer_id == timer_alignment.id()) {
|
||||
Info("Time Alignment Timer expired\n");
|
||||
timer_alignment_expire();
|
||||
} else {
|
||||
Warning("Received callback from unknown timer_id=%d\n", timer_id);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# and at http://www.gnu.org/licenses/.
|
||||
#
|
||||
|
||||
set(SOURCES rrc.cc rrc_procedures.cc)
|
||||
set(SOURCES rrc.cc rrc_procedures.cc rrc_meas.cc)
|
||||
|
||||
add_library(srsue_rrc STATIC ${SOURCES})
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -72,12 +72,12 @@ proc_outcome_t rrc::cell_search_proc::handle_cell_found(const phy_interface_rrc_
|
|||
Info("Cell found in this frequency. Setting new serving cell...\n");
|
||||
|
||||
// Create a cell with NaN RSRP. Will be updated by new_phy_meas() during SIB search.
|
||||
if (not rrc_ptr->add_neighbour_cell(new_cell, NAN)) {
|
||||
if (not rrc_ptr->add_neighbour_cell(unique_cell_t(new cell_t(new_cell)))) {
|
||||
Info("No more space for neighbour cells\n");
|
||||
return proc_outcome_t::success;
|
||||
}
|
||||
|
||||
rrc_ptr->set_serving_cell(new_cell);
|
||||
rrc_ptr->set_serving_cell(new_cell, false);
|
||||
|
||||
if (not rrc_ptr->phy->cell_is_camping()) {
|
||||
Warning("Could not camp on found cell.\n");
|
||||
|
@ -340,11 +340,14 @@ proc_outcome_t rrc::cell_selection_proc::init()
|
|||
neigh_index = 0;
|
||||
cs_result = cs_result_t::no_cell;
|
||||
state = search_state_t::cell_selection;
|
||||
discard_serving = false;
|
||||
return step();
|
||||
}
|
||||
|
||||
proc_outcome_t rrc::cell_selection_proc::step_cell_selection()
|
||||
{
|
||||
Info("Current serving cell: %s\n", rrc_ptr->serving_cell->print().c_str());
|
||||
|
||||
// Neighbour cells are sorted in descending order of RSRP
|
||||
for (; neigh_index < rrc_ptr->neighbour_cells.size(); ++neigh_index) {
|
||||
/*TODO: CHECK that PLMN matches. Currently we don't receive SIB1 of neighbour cells
|
||||
|
@ -356,23 +359,25 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_selection()
|
|||
(rrc_ptr->cell_selection_criteria(rsrp) and rsrp > rrc_ptr->serving_cell->get_rsrp() + 5)) {
|
||||
// currently connected and verifies cell selection criteria
|
||||
// Try to select Cell
|
||||
rrc_ptr->set_serving_cell(rrc_ptr->neighbour_cells.at(neigh_index)->phy_cell);
|
||||
rrc_ptr->set_serving_cell(rrc_ptr->neighbour_cells.at(neigh_index)->phy_cell, discard_serving);
|
||||
discard_serving = false;
|
||||
Info("Selected cell: %s\n", rrc_ptr->serving_cell->print().c_str());
|
||||
rrc_ptr->rrc_log->console("Selected cell: %s\n", rrc_ptr->serving_cell->print().c_str());
|
||||
|
||||
/* BLOCKING CALL */
|
||||
if (rrc_ptr->phy->cell_select(&rrc_ptr->serving_cell->phy_cell)) {
|
||||
Info("Wait PHY to be in-synch\n");
|
||||
state = search_state_t::wait_in_sync;
|
||||
rrc_ptr->phy_sync_state = phy_unknown_sync;
|
||||
return step();
|
||||
} else {
|
||||
rrc_ptr->phy_sync_state = phy_unknown_sync;
|
||||
Error("Could not camp on serving cell.\n");
|
||||
discard_serving = true;
|
||||
// Continue to next neighbour cell
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rrc_ptr->phy_sync_state == phy_in_sync) {
|
||||
if (rrc_ptr->phy_sync_state == phy_in_sync && rrc_ptr->cell_selection_criteria(rrc_ptr->serving_cell->get_rsrp())) {
|
||||
if (not rrc_ptr->phy->cell_is_camping()) {
|
||||
Info("Serving cell %s is in-sync but not camping. Selecting it...\n", rrc_ptr->serving_cell->print().c_str());
|
||||
|
||||
|
@ -381,6 +386,7 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_selection()
|
|||
Info("Selected serving cell OK.\n");
|
||||
} else {
|
||||
rrc_ptr->phy_sync_state = phy_unknown_sync;
|
||||
rrc_ptr->serving_cell->set_rsrp(-INFINITY);
|
||||
Error("Could not camp on serving cell.\n");
|
||||
return proc_outcome_t::error;
|
||||
}
|
||||
|
@ -401,11 +407,20 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_selection()
|
|||
proc_outcome_t rrc::cell_selection_proc::step_wait_in_sync()
|
||||
{
|
||||
if (rrc_ptr->phy_sync_state == phy_in_sync) {
|
||||
Info("PHY is in SYNC\n");
|
||||
if (not rrc_ptr->serv_cell_cfg.launch(&serv_cell_cfg_fut, rrc_ptr->ue_required_sibs)) {
|
||||
return proc_outcome_t::error;
|
||||
if (rrc_ptr->cell_selection_criteria(rrc_ptr->serving_cell->get_rsrp())) {
|
||||
Info("PHY is in SYNC and cell selection passed\n");
|
||||
serv_cell_cfg_fut = rrc_ptr->serv_cell_cfg.get_future();
|
||||
if (not rrc_ptr->serv_cell_cfg.launch(&serv_cell_cfg_fut, rrc_ptr->ue_required_sibs)) {
|
||||
return proc_outcome_t::error;
|
||||
}
|
||||
state = search_state_t::cell_config;
|
||||
} else {
|
||||
Info("PHY is in SYNC but cell selection did not pass. Go back to select step.\n");
|
||||
neigh_index = 0;
|
||||
cs_result = cs_result_t::no_cell;
|
||||
state = search_state_t::cell_selection;
|
||||
discard_serving = true; // Discard this cell
|
||||
}
|
||||
state = search_state_t::cell_config;
|
||||
}
|
||||
return proc_outcome_t::yield;
|
||||
}
|
||||
|
@ -432,6 +447,7 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_config()
|
|||
return proc_outcome_t::yield;
|
||||
}
|
||||
if (serv_cell_cfg_fut.is_success()) {
|
||||
rrc_ptr->rrc_log->console("Selected cell: %s\n", rrc_ptr->serving_cell->print().c_str());
|
||||
Info("All SIBs of serving cell obtained successfully\n");
|
||||
cs_result = cs_result_t::changed_cell;
|
||||
return proc_outcome_t::success;
|
||||
|
@ -476,7 +492,8 @@ rrc::plmn_search_proc::plmn_search_proc(rrc* parent_) : rrc_ptr(parent_), log_h(
|
|||
proc_outcome_t rrc::plmn_search_proc::init()
|
||||
{
|
||||
Info("Starting PLMN search\n");
|
||||
nof_plmns = 0;
|
||||
nof_plmns = 0;
|
||||
cell_search_fut = rrc_ptr->cell_searcher.get_future();
|
||||
if (not rrc_ptr->cell_searcher.launch(&cell_search_fut)) {
|
||||
Error("Failed due to fail to init cell search...\n");
|
||||
return proc_outcome_t::error;
|
||||
|
@ -804,7 +821,7 @@ proc_outcome_t rrc::go_idle_proc::init()
|
|||
{
|
||||
rlc_flush_counter = 0;
|
||||
Info("Starting...\n");
|
||||
return proc_outcome_t::yield;
|
||||
return step();
|
||||
}
|
||||
|
||||
proc_outcome_t rrc::go_idle_proc::step()
|
||||
|
@ -814,8 +831,10 @@ proc_outcome_t rrc::go_idle_proc::step()
|
|||
return proc_outcome_t::success;
|
||||
}
|
||||
|
||||
// If the RLC SRB1 is not suspended
|
||||
// wait for max. 2s for RLC on SRB1 to be flushed
|
||||
if (not rrc_ptr->rlc->has_data(RB_ID_SRB1) || ++rlc_flush_counter > rlc_flush_timeout) {
|
||||
if (rrc_ptr->rlc->is_suspended(RB_ID_SRB1) || not rrc_ptr->rlc->has_data(RB_ID_SRB1) ||
|
||||
++rlc_flush_counter > rlc_flush_timeout) {
|
||||
rrc_ptr->leave_connected();
|
||||
return proc_outcome_t::success;
|
||||
} else {
|
||||
|
@ -854,8 +873,7 @@ proc_outcome_t rrc::cell_reselection_proc::step()
|
|||
Info("Cell Selection completed. Handling its result...\n");
|
||||
switch (*cell_selection_fut.value()) {
|
||||
case cs_result_t::changed_cell:
|
||||
Info("New cell has been selected, start receiving PCCH\n");
|
||||
rrc_ptr->mac->pcch_start_rx();
|
||||
Info("New cell has been selected\n");
|
||||
break;
|
||||
case cs_result_t::no_cell:
|
||||
Warning("Could not find any cell to camp on\n");
|
||||
|
@ -879,7 +897,10 @@ rrc::connection_reest_proc::connection_reest_proc(srsue::rrc* rrc_) : rrc_ptr(rr
|
|||
|
||||
proc_outcome_t rrc::connection_reest_proc::init(asn1::rrc::reest_cause_e cause)
|
||||
{
|
||||
Info("Starting...\n");
|
||||
Info("Starting... Cause: %s\n",
|
||||
cause == asn1::rrc::reest_cause_opts::recfg_fail
|
||||
? "Reconfiguration failure"
|
||||
: cause == asn1::rrc::reest_cause_opts::ho_fail ? "Handover failure" : "Other failure");
|
||||
|
||||
// Save Current RNTI before MAC Reset
|
||||
mac_interface_rrc::ue_rnti_t uernti;
|
||||
|
@ -891,6 +912,7 @@ proc_outcome_t rrc::connection_reest_proc::init(asn1::rrc::reest_cause_e cause)
|
|||
reest_rnti = uernti.crnti;
|
||||
reest_cause = cause;
|
||||
reest_source_pci = rrc_ptr->serving_cell->get_pci(); // needed for reestablishment with another cell
|
||||
reest_source_freq = rrc_ptr->serving_cell->get_earfcn();
|
||||
|
||||
// the initiation of reestablishment procedure as indicates in 3GPP 36.331 Section 5.3.7.2
|
||||
// Cannot be called from here because it has PHY-MAC re-configuration that should be performed in a different thread
|
||||
|
@ -947,9 +969,10 @@ srslte::proc_outcome_t rrc::connection_reest_proc::step_cell_reselection()
|
|||
// Run cell reselection
|
||||
if (not rrc_ptr->cell_reselector.run()) {
|
||||
// Check T311
|
||||
if (!rrc_ptr->t311.is_running()) {
|
||||
if (not rrc_ptr->t311.is_running()) {
|
||||
// Abort procedure if T311 expires
|
||||
Info("T311 expired during cell reselection. Aborting.\n");
|
||||
Info("T311 expired during cell reselection. Going to IDLE.\n");
|
||||
rrc_ptr->start_go_idle();
|
||||
return proc_outcome_t::success;
|
||||
}
|
||||
|
||||
|
@ -964,7 +987,7 @@ srslte::proc_outcome_t rrc::connection_reest_proc::step_cell_reselection()
|
|||
rrc_ptr->serving_cell->has_sib1(),
|
||||
rrc_ptr->serving_cell->has_sib2(),
|
||||
rrc_ptr->serving_cell->has_sib3());
|
||||
std::vector<uint32_t> required_sibs = {1, 2, 3};
|
||||
std::vector<uint32_t> required_sibs = {0, 1, 2};
|
||||
if (!rrc_ptr->serv_cell_cfg.launch(required_sibs)) {
|
||||
Error("Failed to initiate configure serving cell\n");
|
||||
return proc_outcome_t::error;
|
||||
|
@ -991,7 +1014,8 @@ proc_outcome_t rrc::connection_reest_proc::step_cell_configuration()
|
|||
// Check T311
|
||||
if (!rrc_ptr->t311.is_running()) {
|
||||
// Abort procedure if T311 expires
|
||||
Info("T311 expired during cell configuration. Aborting.\n");
|
||||
Info("T311 expired during cell configuration. Going to IDLE.\n");
|
||||
rrc_ptr->start_go_idle();
|
||||
return proc_outcome_t::success;
|
||||
}
|
||||
|
||||
|
@ -1040,10 +1064,17 @@ srslte::proc_outcome_t rrc::connection_reest_proc::cell_criteria()
|
|||
|
||||
// initiate transmission of the RRCConnectionReestablishmentRequest message in accordance with 5.3.7.4;
|
||||
rrc_ptr->send_con_restablish_request(reest_cause, reest_rnti, reest_source_pci);
|
||||
} else {
|
||||
} else if (rrc_ptr->t311.is_running()) {
|
||||
// Upon selecting an inter-RAT cell
|
||||
Info("Reestablishment Cell Selection criteria failed.\n");
|
||||
rrc_ptr->leave_connected();
|
||||
|
||||
// Launch cell reselection
|
||||
if (not rrc_ptr->cell_reselector.launch()) {
|
||||
Error("Failed to initiate a Cell re-selection procedure...\n");
|
||||
return proc_outcome_t::error;
|
||||
}
|
||||
state = state_t::cell_reselection;
|
||||
return proc_outcome_t::yield;
|
||||
}
|
||||
return proc_outcome_t::success;
|
||||
}
|
||||
|
|
|
@ -240,25 +240,28 @@ public:
|
|||
|
||||
void in_sync() override {}
|
||||
void out_of_sync() override {}
|
||||
void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn, int pci) override
|
||||
void new_cell_meas(std::vector<phy_meas_t>& meas) override
|
||||
{
|
||||
if (!cells.count(pci)) {
|
||||
cells[pci].rsrp_min = rsrp;
|
||||
cells[pci].rsrp_max = rsrp;
|
||||
cells[pci].rsrp_avg = rsrp;
|
||||
cells[pci].rsrq_min = rsrq;
|
||||
cells[pci].rsrq_max = rsrq;
|
||||
cells[pci].rsrq_avg = rsrq;
|
||||
cells[pci].count = 1;
|
||||
} else {
|
||||
cells[pci].rsrp_min = SRSLTE_MIN(cells[pci].rsrp_min, rsrp);
|
||||
cells[pci].rsrp_max = SRSLTE_MAX(cells[pci].rsrp_max, rsrp);
|
||||
cells[pci].rsrp_avg = (rsrp + cells[pci].rsrp_avg * cells[pci].count) / (cells[pci].count + 1);
|
||||
for (auto& m : meas) {
|
||||
uint32_t pci = m.pci;
|
||||
if (!cells.count(pci)) {
|
||||
cells[pci].rsrp_min = m.rsrp;
|
||||
cells[pci].rsrp_max = m.rsrp;
|
||||
cells[pci].rsrp_avg = m.rsrp;
|
||||
cells[pci].rsrq_min = m.rsrq;
|
||||
cells[pci].rsrq_max = m.rsrq;
|
||||
cells[pci].rsrq_avg = m.rsrq;
|
||||
cells[pci].count = 1;
|
||||
} else {
|
||||
cells[pci].rsrp_min = SRSLTE_MIN(cells[pci].rsrp_min, m.rsrp);
|
||||
cells[pci].rsrp_max = SRSLTE_MAX(cells[pci].rsrp_max, m.rsrp);
|
||||
cells[pci].rsrp_avg = (m.rsrp + cells[pci].rsrp_avg * cells[pci].count) / (cells[pci].count + 1);
|
||||
|
||||
cells[pci].rsrq_min = SRSLTE_MIN(cells[pci].rsrq_min, rsrq);
|
||||
cells[pci].rsrq_max = SRSLTE_MAX(cells[pci].rsrq_max, rsrq);
|
||||
cells[pci].rsrq_avg = (rsrq + cells[pci].rsrq_avg * cells[pci].count) / (cells[pci].count + 1);
|
||||
cells[pci].count++;
|
||||
cells[pci].rsrq_min = SRSLTE_MIN(cells[pci].rsrq_min, m.rsrq);
|
||||
cells[pci].rsrq_max = SRSLTE_MAX(cells[pci].rsrq_max, m.rsrq);
|
||||
cells[pci].rsrq_avg = (m.rsrq + cells[pci].rsrq_avg * cells[pci].count) / (cells[pci].count + 1);
|
||||
cells[pci].count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -393,7 +396,6 @@ int main(int argc, char** argv)
|
|||
phy_args.estimator_fil_auto = false;
|
||||
phy_args.estimator_fil_order = 4;
|
||||
phy_args.estimator_fil_stddev = 1.0f;
|
||||
phy_args.sic_pss_enabled = false;
|
||||
phy_args.interpolate_subframe_enabled = false;
|
||||
phy_args.nof_rx_ant = 1;
|
||||
phy_args.cfo_is_doppler = true;
|
||||
|
@ -450,6 +452,8 @@ int main(int argc, char** argv)
|
|||
intra_measure.init(&common, &rrc, &logger);
|
||||
intra_measure.set_primary_cell(serving_cell_id, cell_base);
|
||||
|
||||
std::set<uint32_t> pcis_to_meas = {};
|
||||
|
||||
if (earfcn_dl >= 0) {
|
||||
// Create radio log
|
||||
radio_log = std::unique_ptr<srslte::log_filter>(new srslte::log_filter("Radio"));
|
||||
|
@ -490,7 +494,7 @@ int main(int argc, char** argv)
|
|||
|
||||
// Add cell to known cells
|
||||
if (cell_list.empty()) {
|
||||
intra_measure.add_cell(cell.id);
|
||||
pcis_to_meas.insert(cell.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -499,7 +503,7 @@ int main(int argc, char** argv)
|
|||
if (cell_list == "all") {
|
||||
// Add all possible cells
|
||||
for (int i = 0; i < 504; i++) {
|
||||
intra_measure.add_cell(i);
|
||||
pcis_to_meas.insert(i);
|
||||
}
|
||||
} else if (cell_list == "none") {
|
||||
// Do nothing
|
||||
|
@ -516,10 +520,13 @@ int main(int argc, char** argv)
|
|||
while (ss.good()) {
|
||||
std::string substr;
|
||||
getline(ss, substr, ',');
|
||||
intra_measure.add_cell((uint32_t)strtoul(substr.c_str(), nullptr, 10));
|
||||
pcis_to_meas.insert((uint32_t)strtoul(substr.c_str(), nullptr, 10));
|
||||
}
|
||||
}
|
||||
|
||||
// pass cells to measure to intra_measure object
|
||||
intra_measure.set_cells_to_meas(pcis_to_meas);
|
||||
|
||||
// Run loop
|
||||
for (uint32_t sf_idx = 0; sf_idx < duration_execution_s * 1000; sf_idx++) {
|
||||
srslte_dl_sf_cfg_t sf_cfg_dl = {};
|
||||
|
|
|
@ -85,10 +85,13 @@ private:
|
|||
|
||||
void in_sync() override { notify_in_sync(); }
|
||||
void out_of_sync() override { notify_out_of_sync(); }
|
||||
void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn, int pci) override
|
||||
void new_cell_meas(std::vector<phy_meas_t>& meas) override
|
||||
{
|
||||
notify_new_phy_meas();
|
||||
log_h.info("New measurement earfcn=%d; pci=%d; rsrp=%+.1fdBm; rsrq=%+.1fdB;\n", earfcn, pci, rsrp, rsrq);
|
||||
for (auto& m : meas) {
|
||||
notify_new_phy_meas();
|
||||
log_h.info(
|
||||
"New measurement earfcn=%d; pci=%d; rsrp=%+.1fdBm; rsrq=%+.1fdB;\n", m.earfcn, m.pci, m.rsrp, m.rsrq);
|
||||
}
|
||||
}
|
||||
uint16_t get_dl_sched_rnti(uint32_t tti) override { return rnti; }
|
||||
uint16_t get_ul_sched_rnti(uint32_t tti) override { return rnti; }
|
||||
|
@ -491,7 +494,7 @@ int main(int argc, char** argv)
|
|||
auto cell_search_res = phy_test->get_phy_interface_rrc()->cell_search(&phy_cell);
|
||||
TESTASSERT(cell_search_res.found == srsue::phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND);
|
||||
TESTASSERT(phy_test->get_stack()->wait_in_sync(default_timeout));
|
||||
TESTASSERT(memcmp(&phy_cell.cell, &cell, sizeof(srslte_cell_t)) == 0);
|
||||
TESTASSERT(phy_cell.pci == cell.id);
|
||||
|
||||
// 2. Cell select
|
||||
phy_test->get_phy_interface_rrc()->cell_select(&phy_cell);
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch){};
|
||||
|
||||
// Measurements interface
|
||||
void meas_reset();
|
||||
void meas_stop();
|
||||
int meas_start(uint32_t earfcn, int pci = -1);
|
||||
int meas_stop(uint32_t earfcn, int pci = -1);
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ void lte_ttcn3_phy::set_config(srslte::phy_cfg_t& config, uint32_t cc_idx, uint3
|
|||
}
|
||||
|
||||
// Measurements interface
|
||||
void lte_ttcn3_phy::meas_reset(){};
|
||||
void lte_ttcn3_phy::meas_stop(){};
|
||||
|
||||
int lte_ttcn3_phy::meas_start(uint32_t earfcn, int pci)
|
||||
{
|
||||
|
|
|
@ -31,6 +31,10 @@ add_executable(rrc_reconfig_test rrc_reconfig_test.cc)
|
|||
target_link_libraries(rrc_reconfig_test srsue_upper srslte_upper srslte_phy rrc_asn1)
|
||||
add_test(rrc_reconfig_test rrc_reconfig_test)
|
||||
|
||||
add_executable(rrc_meas_test rrc_meas_test.cc)
|
||||
target_link_libraries(rrc_meas_test srsue_rrc srsue_upper srslte_upper srslte_phy rrc_asn1)
|
||||
add_test(rrc_meas_test rrc_meas_test)
|
||||
|
||||
add_executable(nas_test nas_test.cc)
|
||||
target_link_libraries(nas_test srsue_upper srslte_upper srslte_phy rrc_asn1)
|
||||
add_test(nas_test nas_test)
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -36,7 +36,7 @@
|
|||
using namespace asn1;
|
||||
using namespace asn1::rrc;
|
||||
|
||||
void nas_test()
|
||||
int nas_test()
|
||||
{
|
||||
srslte::log_filter log1("NAS");
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
|
@ -93,9 +93,10 @@ void nas_test()
|
|||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int basic_test()
|
||||
int meas_obj_test()
|
||||
{
|
||||
srslte::log_filter log1("RRC");
|
||||
log1.set_level(srslte::LOG_LEVEL_DEBUG);
|
||||
|
@ -154,6 +155,6 @@ int basic_test()
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
TESTASSERT(basic_test() == 0);
|
||||
nas_test();
|
||||
TESTASSERT(meas_obj_test() == 0);
|
||||
TESTASSERT(nas_test() == 0);
|
||||
}
|
||||
|
|
|
@ -298,10 +298,6 @@ enable = false
|
|||
#
|
||||
# interpolate_subframe_enabled: Interpolates in the time domain the channel estimates within 1 subframe. Default is to average.
|
||||
#
|
||||
# sic_pss_enabled: Applies Successive Interference Cancellation to PSS signals when searching for neighbour cells.
|
||||
# Must be disabled if cells have identical channel and timing, for instance if generated from
|
||||
# the same source.
|
||||
#
|
||||
# pdsch_csi_enabled: Stores the Channel State Information and uses it for weightening the softbits. It is only
|
||||
# used in TM1. It is True by default.
|
||||
#
|
||||
|
@ -333,7 +329,6 @@ enable = false
|
|||
#estimator_fil_order = 4
|
||||
#snr_to_cqi_offset = 0.0
|
||||
#interpolate_subframe_enabled = false
|
||||
#sic_pss_enabled = true
|
||||
#pregenerate_signals = false
|
||||
#pdsch_csi_enabled = true
|
||||
#pdsch_8bit_decoder = false
|
||||
|
|
Loading…
Reference in New Issue