diff --git a/srsue/hdr/stack/rrc/rrc_cell.h b/srsue/hdr/stack/rrc/rrc_cell.h index 95ddd3b50..288bf3197 100644 --- a/srsue/hdr/stack/rrc/rrc_cell.h +++ b/srsue/hdr/stack/rrc/rrc_cell.h @@ -28,19 +28,29 @@ namespace srsue { +inline std::string to_string(const srsue::phy_cell_t& c) +{ + char buffer[64]; + snprintf(buffer, 64, "{earfcn=%d, pci=%d}\n", c.earfcn, c.pci); + return {buffer}; +} + class meas_cell { public: - meas_cell() { gettimeofday(&last_update, nullptr); } - explicit meas_cell(phy_cell_t phy_cell_) : meas_cell() { phy_cell = phy_cell_; } + const static int neighbour_timeout_ms = 5000; + + explicit meas_cell(srslte::unique_timer timer); + meas_cell(const phy_cell_t& phy_cell_, srslte::unique_timer timer); // comparison based on pci and earfcn - bool is_valid() { return phy_cell.earfcn != 0 && srslte_cellid_isvalid(phy_cell.pci); } + bool is_valid() const { return phy_cell.earfcn != 0 && srslte_cellid_isvalid(phy_cell.pci); } bool equals(const meas_cell& 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(meas_cell* x) { return rsrp > x->rsrp || std::isnan(rsrp); } + bool greater(const meas_cell* x) const { return rsrp > x->rsrp || std::isnan(rsrp); } + bool greater(const meas_cell& x) const { return rsrp > x.rsrp || std::isnan(rsrp); } bool has_plmn_id(asn1::rrc::plmn_id_s plmn_id) const; uint32_t nof_plmns() const { return has_sib1() ? sib1.cell_access_related_info.plmn_id_list.size() : 0; } @@ -55,7 +65,7 @@ public: if (!std::isnan(rsrp_)) { rsrp = rsrp_; } - gettimeofday(&last_update, nullptr); + timer.run(); } void set_rsrq(float rsrq_) { @@ -74,9 +84,6 @@ public: float get_rsrq() const { return rsrq; } float get_cfo_hz() const { return phy_cell.cfo_hz; } - // TODO: replace with TTI count - uint32_t timeout_secs(struct timeval now) const; - void set_sib1(const asn1::rrc::sib_type1_s& sib1_); void set_sib2(const asn1::rrc::sib_type2_s& sib2_); void set_sib3(const asn1::rrc::sib_type3_s& sib3_); @@ -118,13 +125,12 @@ public: asn1::rrc::sib_type3_s sib3 = {}; asn1::rrc::sib_type13_r9_s sib13 = {}; asn1::rrc::mcch_msg_s mcch = {}; + srslte::unique_timer timer; private: float rsrp = NAN; float rsrq = NAN; - struct timeval last_update = {}; - bool has_valid_sib1 = false; bool has_valid_sib2 = false; bool has_valid_sib3 = false; @@ -168,7 +174,7 @@ public: const static int MAX_NEIGHBOUR_CELLS = 8; typedef std::unique_ptr unique_meas_cell; - meas_cell_list(); + explicit meas_cell_list(srslte::task_sched_handle task_sched_); bool add_meas_cell(const phy_meas_t& meas); bool add_meas_cell(unique_meas_cell cell); @@ -205,7 +211,9 @@ public: private: bool add_neighbour_cell_unsorted(unique_meas_cell cell); - srslte::log_ref log_h{"RRC"}; + // args + srslte::log_ref log_h{"RRC"}; + srslte::task_sched_handle task_sched; unique_meas_cell serv_cell; std::vector neighbour_cells; diff --git a/srsue/src/stack/rrc/rrc.cc b/srsue/src/stack/rrc/rrc.cc index f633fcd0d..3099f46b4 100644 --- a/srsue/src/stack/rrc/rrc.cc +++ b/srsue/src/stack/rrc/rrc.cc @@ -69,7 +69,8 @@ rrc::rrc(stack_interface_rrc* stack_, srslte::task_sched_handle task_sched_) : cell_reselector(this), connection_reest(this), ho_handler(this), - conn_recfg_proc(this) + conn_recfg_proc(this), + meas_cells(task_sched_) {} rrc::~rrc() = default; diff --git a/srsue/src/stack/rrc/rrc_cell.cc b/srsue/src/stack/rrc/rrc_cell.cc index 68838f641..27df0630d 100644 --- a/srsue/src/stack/rrc/rrc_cell.cc +++ b/srsue/src/stack/rrc/rrc_cell.cc @@ -23,6 +23,16 @@ namespace srsue { +meas_cell::meas_cell(srslte::unique_timer timer_) : timer(std::move(timer_)) +{ + timer.set(neighbour_timeout_ms); + timer.run(); +} +meas_cell::meas_cell(const phy_cell_t& phy_cell_, srslte::unique_timer timer) : meas_cell(std::move(timer)) +{ + phy_cell = phy_cell_; +} + srslte::plmn_id_t meas_cell::get_plmn(uint32_t idx) const { if (idx < sib1.cell_access_related_info.plmn_id_list.size() && has_valid_sib1) { @@ -66,15 +76,6 @@ bool meas_cell::is_sib_scheduled(uint32_t sib_index) const return sib_info_map.find(sib_index) != sib_info_map.end(); } -uint32_t meas_cell::timeout_secs(struct timeval now) const -{ - struct timeval t[3]; - memcpy(&t[2], &now, sizeof(struct timeval)); - memcpy(&t[1], &last_update, sizeof(struct timeval)); - get_time_interval(t); - return t[0].tv_sec; -} - bool meas_cell::has_sibs(srslte::span indexes) const { for (uint32_t idx : indexes) { @@ -160,7 +161,10 @@ uint16_t meas_cell::get_mnc() const * Neighbour Cell List ********************************************/ -meas_cell_list::meas_cell_list() : serv_cell(new meas_cell()) {} +meas_cell_list::meas_cell_list(srslte::task_sched_handle task_sched_) : + serv_cell(new meas_cell(task_sched_.get_unique_timer())), + task_sched(task_sched_) +{} meas_cell* meas_cell_list::get_neighbour_cell_handle(uint32_t earfcn, uint32_t pci) { @@ -184,7 +188,7 @@ bool meas_cell_list::add_meas_cell(const rrc_interface_phy_lte::phy_meas_t& meas phy_cell_t phy_cell = {}; phy_cell.earfcn = meas.earfcn; phy_cell.pci = meas.pci; - unique_meas_cell c = unique_meas_cell(new meas_cell(phy_cell)); + unique_meas_cell c = unique_meas_cell(new meas_cell(phy_cell, task_sched.get_unique_timer())); c.get()->set_rsrp(meas.rsrp); c.get()->set_rsrq(meas.rsrq); c.get()->set_cfo(meas.cfo_hz); @@ -296,11 +300,8 @@ void meas_cell_list::log_neighbour_cells() const //! Called by main RRC thread to remove neighbours from which measurements have not been received in a while void meas_cell_list::clean_neighbours() { - struct timeval now; - gettimeofday(&now, nullptr); - for (auto it = neighbour_cells.begin(); it != neighbour_cells.end();) { - if ((*it)->timeout_secs(now) > NEIGHBOUR_TIMEOUT) { + if (it->get()->timer.is_expired()) { log_h->info("Neighbour PCI=%d timed out. Deleting\n", (*it)->get_pci()); it = neighbour_cells.erase(it); } else { diff --git a/srsue/src/stack/rrc/rrc_procedures.cc b/srsue/src/stack/rrc/rrc_procedures.cc index 96b90766a..42336533c 100644 --- a/srsue/src/stack/rrc/rrc_procedures.cc +++ b/srsue/src/stack/rrc/rrc_procedures.cc @@ -90,7 +90,8 @@ proc_outcome_t rrc::cell_search_proc::handle_cell_found(const phy_cell_t& new_ce Info("Cell found in this frequency. Setting new serving cell EARFCN=%d PCI=%d ...\n", new_cell.earfcn, new_cell.pci); // Create a cell with NaN RSRP. Will be updated by new_phy_meas() during SIB search. - if (not rrc_ptr->meas_cells.add_meas_cell(unique_cell_t(new meas_cell(new_cell)))) { + if (not rrc_ptr->meas_cells.add_meas_cell( + unique_cell_t(new meas_cell(new_cell, rrc_ptr->task_sched.get_unique_timer())))) { Error("Could not add new found cell\n"); return proc_outcome_t::error; } diff --git a/srsue/test/upper/rrc_cell_test.cc b/srsue/test/upper/rrc_cell_test.cc index b317d11fe..9e704cc84 100644 --- a/srsue/test/upper/rrc_cell_test.cc +++ b/srsue/test/upper/rrc_cell_test.cc @@ -26,7 +26,8 @@ using namespace srsue; int test_meas_cell() { - meas_cell invalid_cell{}, cell{phy_cell_t{1, 3400}}; + srslte::task_scheduler task_sched; + meas_cell invalid_cell{task_sched.get_unique_timer()}, cell{phy_cell_t{1, 3400}, task_sched.get_unique_timer()}; TESTASSERT(not invalid_cell.is_valid()); TESTASSERT(cell.is_valid()); @@ -40,12 +41,26 @@ int test_meas_cell() cell.set_rsrp(NAN); TESTASSERT(cell.get_rsrp() == -50); + // Test meas timer expiry + for (size_t i = 0; i < meas_cell::neighbour_timeout_ms; ++i) { + TESTASSERT(not cell.timer.is_expired()); + task_sched.tic(); + } + TESTASSERT(cell.timer.is_expired()); + cell.set_rsrp(-20); + for (size_t i = 0; i < meas_cell::neighbour_timeout_ms; ++i) { + TESTASSERT(not cell.timer.is_expired()); + task_sched.tic(); + } + TESTASSERT(cell.timer.is_expired()); + return SRSLTE_SUCCESS; } int test_add_neighbours() { - meas_cell_list list; + srslte::task_scheduler task_sched; + meas_cell_list list{&task_sched}; TESTASSERT(list.nof_neighbours() == 0); TESTASSERT(not list.serving_cell().is_valid()); TESTASSERT(list.get_neighbour_cell_handle(0, 0) == nullptr); @@ -80,6 +95,19 @@ int test_add_neighbours() TESTASSERT(c2 != nullptr and c2->is_valid() and c2->equals(3400, 1)); TESTASSERT(list.nof_neighbours() == 0); + TESTASSERT(list.add_meas_cell(pmeas)); + TESTASSERT(list.nof_neighbours() == 1); + task_sched.tic(); + task_sched.tic(); + list.get_neighbour_cell_handle(3400, 1)->set_rsrp(-20); + for (size_t i = 0; i < meas_cell::neighbour_timeout_ms; ++i) { + TESTASSERT(list.nof_neighbours() == 1); + list.clean_neighbours(); + task_sched.tic(); + } + list.clean_neighbours(); + TESTASSERT(list.nof_neighbours() == 0); + return SRSLTE_SUCCESS; }