diff --git a/srsenb/sib.conf.example b/srsenb/sib.conf.example index 7ca5dafba..69bc9c077 100644 --- a/srsenb/sib.conf.example +++ b/srsenb/sib.conf.example @@ -137,6 +137,56 @@ sib3 = } }; +##################################################################### +# sib6 configuration options (See TS 36.331) +# Contains UTRA neighbor information for inter-rat handover. +# Must be added to sib1::sched_info::si_mapping_info array parameter to be transmitted +# +# t_resel_utra: Cell reselection timer (seconds) +# t_resel_utra_sf: Optional speed dependent ScalingFactor for t_resel_utra. +# sf_medium: Scaling factor if the UE is in Medium Mobility state, one of "0.25", "0.5", "0.75" or "1.0". +# sf_high: Scaling factor if the UE is in High Mobility state, one of "0.25", "0.5", "0.75" or "1.0". +# carrier_freq_list_utra_fdd / carrier_freq_list_utra_tdd: A list of carrier frequencies of UTRA FDD / TDD. +# carrier_freq: The UARFCN for the UTRA carrier frequency. +# cell_resel_prio: Optional absolute priority of the carrier frequency group. +# thresh_x_high: Srclev threshold (dB) to select to a higher-priority RAT/Frequency. +# thresh_x_low: Srclev threshold (dB) to select to a lower-priority RAT/Frequency. +# q_rx_lev_min: Minimum receive level in UTRA cell, ([field_val] * 2) + 1 = [level in dBm]. +# p_max_utra: The maximum allowed transmission power on the (uplink) carrier frequency. +# q_qual_min: Minimum required quality leve in UTRA cell, applicable only for FDD cells. +# +##################################################################### +sib6 = +{ + t_resel_utra = 1; + t_resel_utra_sf = { + sf_medium = "0.25"; + sf_high = "1.0"; + } + carrier_freq_list_utra_fdd = + ( + { + carrier_freq = 9613; + cell_resel_prio = 6; + thresh_x_high = 3; + thresh_x_low = 2; + q_rx_lev_min = -50; + p_max_utra = 4; + q_qual_min = -10; + } + ); + carrier_freq_list_utra_tdd = + ( + { + carrier_freq = 9505; + thresh_x_high = 1; + thresh_x_low = 2; + q_rx_lev_min = -50; + p_max_utra = -3; + } + ); +}; + ##################################################################### # sib7 configuration options (See TS 36.331) # Contains GERAN neighbor information for CSFB and inter-rat handover. diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 2bd58c6b2..94aee179b 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -142,6 +142,111 @@ int field_intra_black_cell_list::parse(libconfig::Setting& root) return 0; } +int field_carrier_freq_list_utra_fdd::parse(libconfig::Setting& root) +{ + data->carrier_freq_list_utra_fdd.resize((uint32_t)root.getLength()); + data->carrier_freq_list_utra_fdd_present = data->carrier_freq_list_utra_fdd.size() > 0; + for (uint32_t i = 0; i < data->carrier_freq_list_utra_fdd.size() && i < ASN1_RRC_MAX_UTRA_FDD_CARRIER; i++) { + unsigned int carrier_freq = 0; + if (!root[i].lookupValue("carrier_freq", carrier_freq)) { + fprintf(stderr, "Missing field `carrier_freq` in carrier_freq_list_utra_fdd=%d\n", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_fdd[i].carrier_freq = carrier_freq; + + unsigned int cell_resel_prio = 0; + if (root[i].lookupValue("cell_resel_prio", cell_resel_prio)) { + data->carrier_freq_list_utra_fdd[i].cell_resel_prio_present = true; + data->carrier_freq_list_utra_fdd[i].cell_resel_prio = cell_resel_prio; + } + + unsigned int thresh_x_high = 0; + if (!root[i].lookupValue("thresh_x_high", thresh_x_high)) { + ERROR("Missing field `thresh_x_high` in carrier_freq_list_utra_fdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_fdd[i].thresh_x_high = thresh_x_high; + + unsigned int thresh_x_low = 0; + if (!root[i].lookupValue("thresh_x_low", thresh_x_low)) { + ERROR("Missing field `thresh_x_low` in carrier_freq_list_utra_fdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_fdd[i].thresh_x_low = thresh_x_low; + + int q_rx_lev_min = 0; + if (!root[i].lookupValue("q_rx_lev_min", q_rx_lev_min)) { + ERROR("Missing field `q_rx_lev_min` in carrier_freq_list_utra_fdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_fdd[i].q_rx_lev_min = q_rx_lev_min; + + int p_max_utra = 0; + if (!root[i].lookupValue("p_max_utra", p_max_utra)) { + ERROR("Missing field `p_max_utra` in carrier_freq_list_utra_fdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_fdd[i].p_max_utra = p_max_utra; + + int q_qual_min = 0; + if (!root[i].lookupValue("q_qual_min", q_qual_min)) { + ERROR("Missing field `q_qual_min` in carrier_freq_list_utra_fdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_fdd[i].q_qual_min = q_qual_min; + } + return 0; +} + +int field_carrier_freq_list_utra_tdd::parse(libconfig::Setting& root) +{ + data->carrier_freq_list_utra_tdd.resize((uint32_t)root.getLength()); + data->carrier_freq_list_utra_tdd_present = data->carrier_freq_list_utra_tdd.size() > 0; + for (uint32_t i = 0; i < data->carrier_freq_list_utra_tdd.size() && i < ASN1_RRC_MAX_UTRA_TDD_CARRIER; i++) { + unsigned int carrier_freq = 0; + if (!root[i].lookupValue("carrier_freq", carrier_freq)) { + fprintf(stderr, "Missing field `carrier_freq` in carrier_freq_list_utra_tdd=%d\n", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_tdd[i].carrier_freq = carrier_freq; + + unsigned int cell_resel_prio = 0; + if (root[i].lookupValue("cell_resel_prio", cell_resel_prio)) { + data->carrier_freq_list_utra_tdd[i].cell_resel_prio_present = true; + data->carrier_freq_list_utra_tdd[i].cell_resel_prio = cell_resel_prio; + } + + unsigned int thresh_x_high = 0; + if (!root[i].lookupValue("thresh_x_high", thresh_x_high)) { + ERROR("Missing field `thresh_x_high` in carrier_freq_list_utra_tdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_tdd[i].thresh_x_high = thresh_x_high; + + unsigned int thresh_x_low = 0; + if (!root[i].lookupValue("thresh_x_low", thresh_x_low)) { + ERROR("Missing field `thresh_x_low` in carrier_freq_list_utra_tdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_tdd[i].thresh_x_low = thresh_x_low; + + int q_rx_lev_min = 0; + if (!root[i].lookupValue("q_rx_lev_min", q_rx_lev_min)) { + ERROR("Missing field `q_rx_lev_min` in carrier_freq_list_utra_tdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_tdd[i].q_rx_lev_min = q_rx_lev_min; + + int p_max_utra = 0; + if (!root[i].lookupValue("p_max_utra", p_max_utra)) { + ERROR("Missing field `p_max_utra` in carrier_freq_list_utra_tdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_tdd[i].p_max_utra = p_max_utra; + } + return 0; +} + int field_carrier_freqs_info_list::parse(libconfig::Setting& root) { data->carrier_freqs_info_list.resize((uint32_t)root.getLength()); @@ -2231,6 +2336,36 @@ int parse_sib4(std::string filename, sib_type4_s* data) return parser::parse_section(std::move(filename), &sib4); } +int parse_sib6(std::string filename, sib_type6_s* data) +{ + parser::section sib6("sib6"); + + // t-ReselectionUTRA + sib6.add_field(new parser::field("t_resel_utra", &data->t_resel_utra)); + + // t-ReselectionUTRA-SF + parser::section t_resel_utra_sf("t_resel_utra_sf"); + sib6.add_subsection(&t_resel_utra_sf); + t_resel_utra_sf.set_optional(&data->t_resel_utra_sf_present); + t_resel_utra_sf.add_field(make_asn1_enum_number_str_parser("sf_medium", &data->t_resel_utra_sf.sf_medium)); + t_resel_utra_sf.add_field(make_asn1_enum_number_str_parser("sf_high", &data->t_resel_utra_sf.sf_high)); + + // carrierFreqListUTRA-FDD + parser::section carrier_freq_list_utra_fdd("carrier_freq_list_utra_fdd"); + sib6.add_subsection(&carrier_freq_list_utra_fdd); + bool dummy_bool = false; + carrier_freq_list_utra_fdd.set_optional(&dummy_bool); + carrier_freq_list_utra_fdd.add_field(new field_carrier_freq_list_utra_fdd(data)); + + // carrierFreqListUTRA-TDD + parser::section carrier_freq_list_utra_tdd("carrier_freq_list_utra_tdd"); + sib6.add_subsection(&carrier_freq_list_utra_tdd); + carrier_freq_list_utra_tdd.set_optional(&dummy_bool); + carrier_freq_list_utra_tdd.add_field(new field_carrier_freq_list_utra_tdd(data)); + + return parser::parse_section(std::move(filename), &sib6); +} + int parse_sib7(std::string filename, sib_type7_s* data) { parser::section sib7("sib7"); @@ -2314,6 +2449,7 @@ int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_co sib_type2_s* sib2 = &rrc_cfg_->sibs[1].set_sib2(); sib_type3_s* sib3 = &rrc_cfg_->sibs[2].set_sib3(); sib_type4_s* sib4 = &rrc_cfg_->sibs[3].set_sib4(); + sib_type6_s* sib6 = &rrc_cfg_->sibs[5].set_sib6(); sib_type7_s* sib7 = &rrc_cfg_->sibs[6].set_sib7(); sib_type9_s* sib9 = &rrc_cfg_->sibs[8].set_sib9(); sib_type13_r9_s* sib13 = &rrc_cfg_->sibs[12].set_sib13_v920(); @@ -2383,6 +2519,13 @@ int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_co } } + // Generate SIB6 if defined in mapping info + if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type6)) { + if (sib_sections::parse_sib6(args_->enb_files.sib_config, sib6) != SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + } + // Generate SIB7 if defined in mapping info if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type7)) { if (sib_sections::parse_sib7(args_->enb_files.sib_config, sib7) != SRSRAN_SUCCESS) { diff --git a/srsenb/src/enb_cfg_parser.h b/srsenb/src/enb_cfg_parser.h index d1f0ae0ae..494217c2f 100644 --- a/srsenb/src/enb_cfg_parser.h +++ b/srsenb/src/enb_cfg_parser.h @@ -54,6 +54,7 @@ int parse_sib1(std::string filename, asn1::rrc::sib_type1_s* data); int parse_sib2(std::string filename, asn1::rrc::sib_type2_s* data); int parse_sib3(std::string filename, asn1::rrc::sib_type3_s* data); int parse_sib4(std::string filename, asn1::rrc::sib_type4_s* data); +int parse_sib6(std::string filename, asn1::rrc::sib_type6_s* data); int parse_sib7(std::string filename, asn1::rrc::sib_type7_s* data); int parse_sib9(std::string filename, asn1::rrc::sib_type9_s* data); int parse_sib13(std::string filename, asn1::rrc::sib_type13_r9_s* data); @@ -140,6 +141,28 @@ private: asn1::rrc::sib_type4_s* data; }; +class field_carrier_freq_list_utra_fdd final : public parser::field_itf +{ +public: + explicit field_carrier_freq_list_utra_fdd(asn1::rrc::sib_type6_s* data_) { data = data_; } + int parse(Setting& root) override; + const char* get_name() override { return "carrier_freq_list_utra_fdd"; } + +private: + asn1::rrc::sib_type6_s* data; +}; + +class field_carrier_freq_list_utra_tdd final : public parser::field_itf +{ +public: + explicit field_carrier_freq_list_utra_tdd(asn1::rrc::sib_type6_s* data_) { data = data_; } + int parse(Setting& root) override; + const char* get_name() override { return "carrier_freq_list_utra_tdd"; } + +private: + asn1::rrc::sib_type6_s* data; +}; + class field_carrier_freqs_info_list final : public parser::field_itf { public: