diff --git a/srsenb/sib.conf.example b/srsenb/sib.conf.example index 69bc9c077..c38cdbeb2 100644 --- a/srsenb/sib.conf.example +++ b/srsenb/sib.conf.example @@ -137,6 +137,71 @@ sib3 = } }; +##################################################################### +# sib5 configuration options (See TS 36.331) +# Contains information relevant for inter-frequency cell re-selection. +# Must be added to sib1::sched_info::si_mapping_info array parameter to be transmitted +# +# inter_freq_carrier_freq_list: A list of neighbouring inter-frequencies. +# dl_carrier_freq: The EARFCN for the EUTRA carrier frequency. +# q_rx_lev_min: Minimum received RSRP level in the E-UTRA cell, ([field_val] * 2) = [level in dBm]. +# p_max: Optional maximum allowed transmission power for the neighbouring E-UTRA cells on this carrier frequency. +# t_resel_eutra: Cell reselection timer (seconds). +# t_resel_eutra_sf: Optional speed dependent ScalingFactor for t_resel_eutra. +# 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". +# 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. +# allowed_meas_bw: Maximum allowed measurement bandwidth on a carrier frequency . +# presence_ant_port_1: whether all the neighbouring cells use Antenna Port 1. +# cell_resel_prio: Optional absolute priority of the carrier frequency group. +# neigh_cell_cfg: Information related to MBSFN and TDD UL/DL configuration of neighbour cells. +# q_offset_freq: Frequency specific offset for equal priority E-UTRAN frequencies. +# inter_freq_neigh_cell_list: A List of inter-frequency neighbouring cells with specific cell re-selection parameters. +# phys_cell_id: Physical layer identity of the cell. +# q_offset_cell: Cell spcific offset. +# inter_freq_black_cell_list: A List of blacklisted inter-frequency neighbouring cells. +# start: The lowest physical cell identity in the range. +# range: The number of physical cell identities in the range. +# +##################################################################### +sib5 = +{ + inter_freq_carrier_freq_list = + ( + { + dl_carrier_freq = 1450; + q_rx_lev_min = -70; + t_resel_eutra = 2; + t_resel_eutra_sf = { + sf_medium = "0.25"; + sf_high = "1.0"; + }; + thresh_x_high = 3; + thresh_x_low = 2; + allowed_meas_bw = 75; + presence_ant_port_1 = True; + cell_resel_prio = 4; + neigh_cell_cfg = 2; + q_offset_freq = -6; + inter_freq_neigh_cell_list = + ( + { + phys_cell_id = 500; + q_offset_cell = 2; + } + ); + inter_freq_black_cell_list = + ( + { + start = 123; + range = 4; + } + ); + } + ); +}; + ##################################################################### # sib6 configuration options (See TS 36.331) # Contains UTRA neighbor information for inter-rat handover. diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 40d74c44b..812d6d1f6 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -142,6 +142,156 @@ int field_intra_black_cell_list::parse(libconfig::Setting& root) return 0; } +int field_inter_freq_carrier_freq_list::parse(libconfig::Setting& root) +{ + data->inter_freq_carrier_freq_list.resize((uint32_t)root.getLength()); + for (uint32_t i = 0; i < data->inter_freq_carrier_freq_list.size() && i < ASN1_RRC_MAX_FREQ; i++) { + unsigned int dl_carrier_freq = 0; + if (!root[i].lookupValue("dl_carrier_freq", dl_carrier_freq)) { + ERROR("Missing field `dl_carrier_freq` in inter_freq_carrier_freq_list=%d", i); + return SRSRAN_ERROR; + } + data->inter_freq_carrier_freq_list[i].dl_carrier_freq = dl_carrier_freq; + + 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 inter_freq_carrier_freq_list=%d", i); + return SRSRAN_ERROR; + } + data->inter_freq_carrier_freq_list[i].q_rx_lev_min = q_rx_lev_min; + + int p_max = 0; + if (root[i].lookupValue("p_max", p_max)) { + data->inter_freq_carrier_freq_list[i].p_max_present = true; + data->inter_freq_carrier_freq_list[i].p_max = p_max; + } + + unsigned int t_resel_eutra = 0; + if (!root[i].lookupValue("t_resel_eutra", t_resel_eutra)) { + ERROR("Missing field `t_resel_eutra` in inter_freq_carrier_freq_list=%d", i); + return SRSRAN_ERROR; + } + data->inter_freq_carrier_freq_list[i].t_resel_eutra = t_resel_eutra; + + if (root[i].exists("t_resel_eutra_sf")) { + data->inter_freq_carrier_freq_list[i].t_resel_eutra_sf_present = true; + + field_asn1_enum_number_str sf_medium( + "sf_medium", &data->inter_freq_carrier_freq_list[i].t_resel_eutra_sf.sf_medium); + if (sf_medium.parse(root[i]["t_resel_eutra_sf"])) { + ERROR("Error parsing `sf_medium` in inter_freq_carrier_freq_list=%d t_resel_eutra_sf", i); + return SRSRAN_ERROR; + } + + field_asn1_enum_number_str sf_high( + "sf_high", &data->inter_freq_carrier_freq_list[i].t_resel_eutra_sf.sf_high); + if (sf_high.parse(root[i]["t_resel_eutra_sf"])) { + ERROR("Error parsing `sf_high` in inter_freq_carrier_freq_list=%d t_resel_eutra_sf", i); + return SRSRAN_ERROR; + } + } + + unsigned int thresh_x_high = 0; + if (!root[i].lookupValue("thresh_x_high", thresh_x_high)) { + ERROR("Missing field `thresh_x_high` in inter_freq_carrier_freq_list=%d", i); + return SRSRAN_ERROR; + } + data->inter_freq_carrier_freq_list[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 inter_freq_carrier_freq_list=%d", i); + return SRSRAN_ERROR; + } + data->inter_freq_carrier_freq_list[i].thresh_x_low = thresh_x_low; + + field_asn1_enum_number allowed_meas_bw( + "allowed_meas_bw", &data->inter_freq_carrier_freq_list[i].allowed_meas_bw); + if (allowed_meas_bw.parse(root[i])) { + ERROR("Error parsing `allowed_meas_bw` in inter_freq_carrier_freq_list=%d", i); + return SRSRAN_ERROR; + } + + bool presence_ant_port1 = 0; + if (!root[i].lookupValue("presence_ant_port_1", presence_ant_port1)) { + ERROR("Missing field `presence_ant_port_1` in inter_freq_carrier_freq_list=%d", i); + return SRSRAN_ERROR; + } + data->inter_freq_carrier_freq_list[i].presence_ant_port1 = presence_ant_port1; + + unsigned int cell_resel_prio = 0; + if (root[i].lookupValue("cell_resel_prio", cell_resel_prio)) { + data->inter_freq_carrier_freq_list[i].cell_resel_prio_present = true; + data->inter_freq_carrier_freq_list[i].cell_resel_prio = cell_resel_prio; + } + + field_asn1_enum_number q_offset_freq( + "q_offset_freq", &data->inter_freq_carrier_freq_list[i].q_offset_freq); + if (!q_offset_freq.parse(root[i])) { + data->inter_freq_carrier_freq_list[i].q_offset_freq_present = true; + } + + field_asn1_bitstring_number, uint8_t> neigh_cell_cfg( + "neigh_cell_cfg", &data->inter_freq_carrier_freq_list[i].neigh_cell_cfg); + if (neigh_cell_cfg.parse(root[i])) { + ERROR("Error parsing `neigh_cell_cfg` in inter_freq_carrier_freq_list=%d", i); + return SRSRAN_ERROR; + } + + if (root[i].exists("inter_freq_neigh_cell_list")) { + auto inter_neigh_cell_list_parser = new field_inter_freq_neigh_cell_list(&data->inter_freq_carrier_freq_list[i]); + HANDLEPARSERCODE(inter_neigh_cell_list_parser->parse(root[i]["inter_freq_neigh_cell_list"])); + } + + if (root[i].exists("inter_freq_black_cell_list")) { + auto inter_black_cell_list_parser = new field_inter_freq_black_cell_list(&data->inter_freq_carrier_freq_list[i]); + HANDLEPARSERCODE(inter_black_cell_list_parser->parse(root[i]["inter_freq_black_cell_list"])); + } + } + return 0; +} + +int field_inter_freq_neigh_cell_list::parse(libconfig::Setting& root) +{ + data->inter_freq_neigh_cell_list.resize((uint32_t)root.getLength()); + data->inter_freq_neigh_cell_list_present = data->inter_freq_neigh_cell_list.size() > 0; + for (uint32_t i = 0; i < data->inter_freq_neigh_cell_list.size() && i < ASN1_RRC_MAX_CELL_BLACK; i++) { + if (not parse_enum_by_number(data->inter_freq_neigh_cell_list[i].q_offset_cell, "q_offset_cell", root[i])) { + ERROR("Missing field q_offset_cell in neigh_cell=%d\n", i); + return SRSRAN_ERROR; + } + + unsigned int phys_cell_id = 0; + if (!root[i].lookupValue("phys_cell_id", phys_cell_id)) { + ERROR("Missing field phys_cell_id in neigh_cell=%d\n", i); + return SRSRAN_ERROR; + } + data->inter_freq_neigh_cell_list[i].pci = (uint16)phys_cell_id; + } + return 0; +} + +int field_inter_freq_black_cell_list::parse(libconfig::Setting& root) +{ + data->inter_freq_black_cell_list.resize((uint32_t)root.getLength()); + data->inter_freq_black_cell_list_present = data->inter_freq_black_cell_list.size() > 0; + for (uint32_t i = 0; i < data->inter_freq_black_cell_list.size() && i < ASN1_RRC_MAX_CELL_BLACK; i++) { + if (not parse_enum_by_number(data->inter_freq_black_cell_list[i].range, "range", root[i])) { + ERROR("Missing field range in black_cell=%d\n", i); + return SRSRAN_ERROR; + } + data->inter_freq_black_cell_list[i].range_present = true; + + unsigned int start = 0; + if (!root[i].lookupValue("start", start)) { + ERROR("Missing field start in black_cell=%d\n", i); + return SRSRAN_ERROR; + } + data->inter_freq_black_cell_list[i].start = (uint16)start; + } + return 0; +} + int field_carrier_freq_list_utra_fdd::parse(libconfig::Setting& root) { data->carrier_freq_list_utra_fdd.resize((uint32_t)root.getLength()); @@ -2336,6 +2486,20 @@ int parse_sib4(std::string filename, sib_type4_s* data) return parser::parse_section(std::move(filename), &sib4); } +int parse_sib5(std::string filename, sib_type5_s* data) +{ + parser::section sib5("sib5"); + + // interFreqCarrierFreqList + parser::section inter_freq_carrier_freq_list("inter_freq_carrier_freq_list"); + sib5.add_subsection(&inter_freq_carrier_freq_list); + bool dummy_bool = false; + inter_freq_carrier_freq_list.set_optional(&dummy_bool); + inter_freq_carrier_freq_list.add_field(new field_inter_freq_carrier_freq_list(data)); + + return parser::parse_section(std::move(filename), &sib5); +} + int parse_sib6(std::string filename, sib_type6_s* data) { parser::section sib6("sib6"); @@ -2449,6 +2613,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_type5_s* sib5 = &rrc_cfg_->sibs[4].set_sib5(); 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(); @@ -2519,6 +2684,13 @@ int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_co } } + // Generate SIB5 if defined in mapping info + if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type5)) { + if (sib_sections::parse_sib5(args_->enb_files.sib_config, sib5) != SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + } + // 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) { diff --git a/srsenb/src/enb_cfg_parser.h b/srsenb/src/enb_cfg_parser.h index 494217c2f..08c3e1b71 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_sib5(std::string filename, asn1::rrc::sib_type5_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); @@ -141,6 +142,39 @@ private: asn1::rrc::sib_type4_s* data; }; +class field_inter_freq_carrier_freq_list final : public parser::field_itf +{ +public: + explicit field_inter_freq_carrier_freq_list(asn1::rrc::sib_type5_s* data_) { data = data_; } + int parse(Setting& root) override; + const char* get_name() override { return "inter_freq_carrier_freq_list"; } + +private: + asn1::rrc::sib_type5_s* data; +}; + +class field_inter_freq_neigh_cell_list final : public parser::field_itf +{ +public: + explicit field_inter_freq_neigh_cell_list(asn1::rrc::inter_freq_carrier_freq_info_s* data_) { data = data_; } + int parse(Setting& root) override; + const char* get_name() override { return "inter_freq_neigh_cell_list"; } + +private: + asn1::rrc::inter_freq_carrier_freq_info_s* data; +}; + +class field_inter_freq_black_cell_list final : public parser::field_itf +{ +public: + explicit field_inter_freq_black_cell_list(asn1::rrc::inter_freq_carrier_freq_info_s* data_) { data = data_; } + int parse(Setting& root) override; + const char* get_name() override { return "inter_freq_black_cell_list"; } + +private: + asn1::rrc::inter_freq_carrier_freq_info_s* data; +}; + class field_carrier_freq_list_utra_fdd final : public parser::field_itf { public: