/* * Copyright 2013-2020 Software Radio Systems Limited * * This file is part of srsLTE. * * srsLTE is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * srsLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * A copy of the GNU Affero General Public License can be found in * the LICENSE file in the top-level directory of this distribution * and at http://www.gnu.org/licenses/. * */ #ifndef SRSLTE_RRC_CELL_H #define SRSLTE_RRC_CELL_H #include "srslte/asn1/rrc_asn1.h" #include "srslte/asn1/rrc_asn1_utils.h" #include "srslte/interfaces/ue_interfaces.h" namespace srsue { class cell_t { public: cell_t() { gettimeofday(&last_update, nullptr); } explicit cell_t(phy_cell_t phy_cell_) : cell_t() { phy_cell = phy_cell_; } // comparison based on pci and earfcn bool is_valid() { return phy_cell.earfcn != 0 && srslte_cellid_isvalid(phy_cell.pci); } bool equals(const 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 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; } srslte::plmn_id_t get_plmn(uint32_t idx) const; uint16_t get_tac() const { return has_sib1() ? (uint16_t)sib1.cell_access_related_info.tac.to_number() : 0; } uint32_t get_earfcn() const { return phy_cell.earfcn; } uint32_t get_pci() const { return phy_cell.pci; } void set_rsrp(float rsrp_) { if (!std::isnan(rsrp_)) { rsrp = rsrp_; } gettimeofday(&last_update, nullptr); } void set_rsrq(float rsrq_) { if (!std::isnan(rsrq_)) { rsrq = rsrq_; } } void set_cfo(float cfo_Hz_) { if (not std::isnan(cfo_Hz_) && not std::isinf(cfo_Hz_)) { phy_cell.cfo_hz = cfo_Hz_; } } float get_rsrp() const { return rsrp; } 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_); void set_sib13(const asn1::rrc::sib_type13_r9_s& sib13_); const asn1::rrc::sib_type1_s* sib1ptr() const { return has_sib1() ? &sib1 : nullptr; } const asn1::rrc::sib_type2_s* sib2ptr() const { return has_sib2() ? &sib2 : nullptr; } const asn1::rrc::sib_type3_s* sib3ptr() const { return has_sib3() ? &sib3 : nullptr; } const asn1::rrc::sib_type13_r9_s* sib13ptr() const { return has_sib13() ? &sib13 : nullptr; } uint32_t get_cell_id() const { return (uint32_t)sib1.cell_access_related_info.cell_id.to_number(); } bool has_sib(uint32_t index) const; bool has_sib1() const { return has_valid_sib1; } bool has_sib2() const { return has_valid_sib2; } bool has_sib3() const { return has_valid_sib3; } bool has_sib13() const { return has_valid_sib13; } void reset_sibs() { has_valid_sib1 = false; has_valid_sib2 = false; has_valid_sib3 = false; has_valid_sib13 = false; } uint16_t get_mcc() const; uint16_t get_mnc() const; std::string to_string() const; bool is_sib_scheduled(uint32_t sib_index) const; phy_cell_t phy_cell = {0, 0, 0}; bool has_mcch = false; asn1::rrc::sib_type1_s sib1 = {}; asn1::rrc::sib_type2_s sib2 = {}; asn1::rrc::sib_type3_s sib3 = {}; asn1::rrc::sib_type13_r9_s sib13 = {}; asn1::rrc::mcch_msg_s mcch = {}; 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; bool has_valid_sib13 = false; std::map sib_info_map; ///< map of sib_index to index of schedInfoList in SIB1 }; //! Universal methods to extract pci/earfcn and compare the two values template uint32_t get_pci(const T& t) { return t.pci; } template <> inline uint32_t get_pci(const cell_t& t) { return t.get_pci(); } template uint32_t get_earfcn(const T& t) { return t.earfcn; } template <> inline uint32_t get_earfcn(const cell_t& t) { return t.get_earfcn(); } template bool is_same_cell(const T& lhs, const U& rhs) { return get_pci(lhs) == get_pci(rhs) and get_earfcn(lhs) == get_earfcn(rhs); } class meas_cell_list { using phy_meas_t = rrc_interface_phy_lte::phy_meas_t; public: const static int NEIGHBOUR_TIMEOUT = 5; const static int MAX_NEIGHBOUR_CELLS = 8; typedef std::unique_ptr unique_cell_t; meas_cell_list(); bool add_meas_cell(const phy_meas_t& meas); bool add_meas_cell(unique_cell_t cell); void rem_last_neighbour(); unique_cell_t remove_neighbour_cell(uint32_t earfcn, uint32_t pci); void clean_neighbours(); void sort_neighbour_cells(); bool process_new_cell_meas(const std::vector& meas, const std::function& filter_meas); cell_t* get_neighbour_cell_handle(uint32_t earfcn, uint32_t pci); const cell_t* get_neighbour_cell_handle(uint32_t earfcn, uint32_t pci) const; void log_neighbour_cells() const; std::string print_neighbour_cells() const; std::set get_neighbour_pcis(uint32_t earfcn) const; bool has_neighbour_cell(uint32_t earfcn, uint32_t pci) const; size_t nof_neighbours() const { return neighbour_cells.size(); } cell_t& operator[](size_t idx) { return *neighbour_cells[idx]; } const cell_t& operator[](size_t idx) const { return *neighbour_cells[idx]; } cell_t& at(size_t idx) { return *neighbour_cells.at(idx); } cell_t* find_cell(uint32_t earfcn, uint32_t pci); // serving cell handling int set_serving_cell(phy_cell_t phy_cell, bool discard_serving); cell_t& serving_cell() { return *serv_cell; } const cell_t& serving_cell() const { return *serv_cell; } using iterator = std::vector::iterator; iterator begin() { return neighbour_cells.begin(); } iterator end() { return neighbour_cells.end(); } private: bool add_neighbour_cell_unsorted(unique_cell_t cell); srslte::log_ref log_h{"RRC"}; unique_cell_t serv_cell; std::vector neighbour_cells; }; } // namespace srsue #endif // SRSLTE_RRC_CELL_H