diff --git a/srsenb/hdr/enb.h b/srsenb/hdr/enb.h index f58007747..73bf7cc4e 100644 --- a/srsenb/hdr/enb.h +++ b/srsenb/hdr/enb.h @@ -134,9 +134,8 @@ public: // eNodeB metrics interface bool get_metrics(enb_metrics_t* m); - private: - static enb *instance; + static enb* instance; const static int ENB_POOL_SIZE = 1024*10; @@ -169,18 +168,7 @@ private: srslte::LOG_LEVEL_ENUM level(std::string l); // bool check_srslte_version(); - 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_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); - int parse_sibs(all_args_t* args, rrc_cfg_t* rrc_cfg, phy_cfg_t* phy_config_common); - int parse_rr(all_args_t* args, rrc_cfg_t* rrc_cfg); - int parse_drb(all_args_t* args, rrc_cfg_t* rrc_cfg); - bool sib_is_present(const asn1::rrc::sched_info_list_l& l, asn1::rrc::sib_type_e sib_num); - int parse_cell_cfg(all_args_t* args, srslte_cell_t* cell); + int parse_cell_cfg(all_args_t* args, srslte_cell_t* cell); std::string get_build_mode(); std::string get_build_info(); diff --git a/srsenb/hdr/phy/phy.h b/srsenb/hdr/phy/phy.h index c452aa592..4e80d47a9 100644 --- a/srsenb/hdr/phy/phy.h +++ b/srsenb/hdr/phy/phy.h @@ -35,15 +35,15 @@ #include "txrx.h" namespace srsenb { - -typedef struct { + +struct phy_cfg_t { srslte_cell_t cell; asn1::rrc::prach_cfg_sib_s prach_cnfg; asn1::rrc::pdsch_cfg_common_s pdsch_cnfg; asn1::rrc::pusch_cfg_common_s pusch_cnfg; asn1::rrc::pucch_cfg_common_s pucch_cnfg; asn1::rrc::srs_ul_cfg_common_c srs_ul_cnfg; -} phy_cfg_t; +}; class phy : public enb_phy_base, public phy_interface_stack_lte, public srslte::phy_interface_radio { diff --git a/srsenb/hdr/stack/rrc/rrc.h b/srsenb/hdr/stack/rrc/rrc.h index 79e6e1f0d..67f14f017 100644 --- a/srsenb/hdr/stack/rrc/rrc.h +++ b/srsenb/hdr/stack/rrc/rrc.h @@ -146,15 +146,15 @@ public: rrc(); ~rrc(); - void init(rrc_cfg_t* cfg, - phy_interface_stack_lte* phy, - mac_interface_rrc* mac, - rlc_interface_rrc* rlc, - pdcp_interface_rrc* pdcp, - s1ap_interface_rrc* s1ap, - gtpu_interface_rrc* gtpu, - srslte::timer_handler* timers_, - srslte::log* log_rrc); + void init(rrc_cfg_t* cfg, + phy_interface_rrc_lte* phy, + mac_interface_rrc* mac, + rlc_interface_rrc* rlc, + pdcp_interface_rrc* pdcp, + s1ap_interface_rrc* s1ap, + gtpu_interface_rrc* gtpu, + srslte::timer_handler* timers_, + srslte::log* log_rrc); void stop(); void get_metrics(rrc_metrics_t& m); @@ -342,7 +342,7 @@ private: // args srslte::timer_handler* timers = nullptr; srslte::byte_buffer_pool* pool = nullptr; - phy_interface_stack_lte* phy = nullptr; + phy_interface_rrc_lte* phy = nullptr; mac_interface_rrc* mac = nullptr; rlc_interface_rrc* rlc = nullptr; pdcp_interface_rrc* pdcp = nullptr; @@ -407,7 +407,7 @@ private: sr_sched_t sr_sched = {}; sr_sched_t cqi_sched = {}; asn1::rrc::mcch_msg_s mcch; - bool enable_mbms = false; + bool enable_mbms = false; rrc_cfg_t cfg = {}; uint32_t nof_si_messages = 0; asn1::rrc::sib_type2_s sib2; diff --git a/srsenb/src/CMakeLists.txt b/srsenb/src/CMakeLists.txt index 7ef4bcd85..1451c502c 100644 --- a/srsenb/src/CMakeLists.txt +++ b/srsenb/src/CMakeLists.txt @@ -33,8 +33,9 @@ if (RPATH) SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) endif (RPATH) +add_library(enb_cfg_parser parser.cc enb_cfg_parser.cc) -add_executable(srsenb main.cc enb.cc parser.cc enb_cfg_parser.cc metrics_stdout.cc metrics_csv.cc) +add_executable(srsenb main.cc enb.cc metrics_stdout.cc metrics_csv.cc) target_link_libraries(srsenb srsenb_radio srsenb_phy srsenb_stack @@ -46,6 +47,7 @@ target_link_libraries(srsenb srsenb_radio srslte_upper srslte_radio rrc_asn1 + enb_cfg_parser ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} ${SEC_LIBRARIES} diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc index a07715414..bb32638e4 100644 --- a/srsenb/src/enb.cc +++ b/srsenb/src/enb.cc @@ -22,6 +22,7 @@ #include "srsenb/hdr/enb.h" #include "srsenb/hdr/radio/enb_radio_multi.h" #include "srsenb/hdr/stack/enb_stack_lte.h" +#include "srsenb/src/enb_cfg_parser.h" #include "srslte/build_info.h" #include #include @@ -39,7 +40,7 @@ enb* enb::get_instance() instance = new enb(); } pthread_mutex_unlock(&enb_instance_mutex); - return(instance); + return (instance); } void enb::cleanup() { @@ -61,10 +62,7 @@ enb::enb() : started(false), pool(srslte::byte_buffer_pool::get_instance(ENB_POO srslte_dft_load(); } -enb::~enb() -{ - -} +enb::~enb() {} int enb::init(const all_args_t& args_) { @@ -164,115 +162,16 @@ int enb::parse_args(const all_args_t& args_) { // set member variable args = args_; - - // Parse config files - srslte_cell_t cell_cfg = {}; - - if (parse_cell_cfg(&args, &cell_cfg)) { - fprintf(stderr, "Error parsing Cell configuration\n"); - return SRSLTE_ERROR; - } - if (parse_sibs(&args, &rrc_cfg, &phy_cfg)) { - fprintf(stderr, "Error parsing SIB configuration\n"); - return SRSLTE_ERROR; - } - if (parse_rr(&args, &rrc_cfg)) { - fprintf(stderr, "Error parsing Radio Resources configuration\n"); - return SRSLTE_ERROR; - } - if (parse_drb(&args, &rrc_cfg)) { - fprintf(stderr, "Error parsing DRB configuration\n"); - return SRSLTE_ERROR; - } - - if (args.enb.transmission_mode == 1) { - phy_cfg.pdsch_cnfg.p_b = 0; // Default TM1 - rrc_cfg.sibs[1].sib2().rr_cfg_common.pdsch_cfg_common.p_b = 0; - } else { - phy_cfg.pdsch_cnfg.p_b = 1; // Default TM2,3,4 - rrc_cfg.sibs[1].sib2().rr_cfg_common.pdsch_cfg_common.p_b = 1; - } - - rrc_cfg.inactivity_timeout_ms = args.general.rrc_inactivity_timer; - rrc_cfg.enable_mbsfn = args.stack.embms.enable; - - rrc_cfg.dl_earfcn = args.enb.dl_earfcn; - rrc_cfg.pci = args.enb.pci; - - // Check number of control symbols - if (cell_cfg.nof_prb < 50 && args.stack.mac.sched.nof_ctrl_symbols != 3) { - args.stack.mac.sched.nof_ctrl_symbols = 3; - fprintf(stdout, - "Setting number of control symbols to %d for %d PRB cell.\n", - args.stack.mac.sched.nof_ctrl_symbols, - cell_cfg.nof_prb); - } - - // Parse EEA preference list - std::vector eea_pref_list; - boost::split(eea_pref_list, args.general.eea_pref_list, boost::is_any_of(",")); - int i = 0; - for (auto it = eea_pref_list.begin(); it != eea_pref_list.end() && i < srslte::CIPHERING_ALGORITHM_ID_N_ITEMS; it++) { - boost::trim_left(*it); - if ((*it) == "EEA0") { - rrc_cfg.eea_preference_list[i] = srslte::CIPHERING_ALGORITHM_ID_EEA0; - i++; - } else if ((*it) == "EEA1") { - rrc_cfg.eea_preference_list[i] = srslte::CIPHERING_ALGORITHM_ID_128_EEA1; - i++; - } else if ((*it) == "EEA2") { - rrc_cfg.eea_preference_list[i] = srslte::CIPHERING_ALGORITHM_ID_128_EEA2; - i++; - } else if ((*it) == "EEA3") { - rrc_cfg.eea_preference_list[i] = srslte::CIPHERING_ALGORITHM_ID_128_EEA3; - i++; - } else { - fprintf(stderr, "Failed to parse EEA prefence list %s \n", args.general.eea_pref_list.c_str()); - return SRSLTE_ERROR; - } - } - - // Parse EIA preference list - std::vector eia_pref_list; - boost::split(eia_pref_list, args.general.eia_pref_list, boost::is_any_of(",")); - i = 0; - for (auto it = eia_pref_list.begin(); it != eia_pref_list.end() && i < srslte::INTEGRITY_ALGORITHM_ID_N_ITEMS; it++) { - boost::trim_left(*it); - if ((*it) == "EIA0") { - rrc_cfg.eia_preference_list[i] = srslte::INTEGRITY_ALGORITHM_ID_EIA0; - i++; - } else if ((*it) == "EIA1") { - rrc_cfg.eia_preference_list[i] = srslte::INTEGRITY_ALGORITHM_ID_128_EIA1; - i++; - } else if ((*it) == "EIA2") { - rrc_cfg.eia_preference_list[i] = srslte::INTEGRITY_ALGORITHM_ID_128_EIA2; - i++; - } else if ((*it) == "EIA3") { - rrc_cfg.eia_preference_list[i] = srslte::INTEGRITY_ALGORITHM_ID_128_EIA3; - i++; - } else { - fprintf(stderr, "Failed to parse EIA prefence list %s \n", args.general.eia_pref_list.c_str()); - return SRSLTE_ERROR; - } - } - - // Copy cell struct to rrc and phy - rrc_cfg.cell = cell_cfg; - phy_cfg.cell = cell_cfg; - - // Patch certain args that are not exposed yet - args.rf.nof_radios = 1; - args.rf.nof_rf_channels = args.phy.nof_carriers; - args.rf.nof_rx_ant = args.enb.nof_ports; - - return SRSLTE_SUCCESS; + return enb_conf_sections::parse_cfg_files(&args, &rrc_cfg, &phy_cfg); } -void enb::start_plot() { +void enb::start_plot() +{ phy->start_plot(); } -void enb::print_pool() { +void enb::print_pool() +{ srslte::byte_buffer_pool::get_instance()->print_all_buffers(); } @@ -288,17 +187,17 @@ bool enb::get_metrics(enb_metrics_t* m) srslte::LOG_LEVEL_ENUM enb::level(std::string l) { boost::to_upper(l); - if("NONE" == l){ + if ("NONE" == l) { return srslte::LOG_LEVEL_NONE; - }else if("ERROR" == l){ + } else if ("ERROR" == l) { return srslte::LOG_LEVEL_ERROR; - }else if("WARNING" == l){ + } else if ("WARNING" == l) { return srslte::LOG_LEVEL_WARNING; - }else if("INFO" == l){ + } else if ("INFO" == l) { return srslte::LOG_LEVEL_INFO; - }else if("DEBUG" == l){ + } else if ("DEBUG" == l) { return srslte::LOG_LEVEL_DEBUG; - }else{ + } else { return srslte::LOG_LEVEL_NONE; } } diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 9ef117ed6..fae67a468 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -21,9 +21,11 @@ #include "enb_cfg_parser.h" #include "srsenb/hdr/cfg_parser.h" +#include "srsenb/hdr/enb.h" #include "srslte/asn1/rrc_asn1_utils.h" #include "srslte/phy/common/phy_common.h" #include "srslte/srslte.h" +#include #define HANDLEPARSERCODE(cond) \ do { \ @@ -44,32 +46,16 @@ using namespace asn1::rrc; namespace srsenb { -int enb::parse_cell_cfg(all_args_t* args_, srslte_cell_t* cell) +bool sib_is_present(const sched_info_list_l& l, sib_type_e sib_num) { - cell->frame_type = SRSLTE_FDD; - cell->id = args_->enb.pci; - cell->cp = SRSLTE_CP_NORM; - cell->nof_ports = args_->enb.nof_ports; - cell->nof_prb = args_->enb.n_prb; - - phich_cfg_s phichcfg; - - parser::section phy_cnfg("phy_cnfg"); - parser::section phich_cnfg("phich_cnfg"); - phy_cnfg.add_subsection(&phich_cnfg); - phich_cnfg.add_field(make_asn1_enum_str_parser("duration", &phichcfg.phich_dur)); - phich_cnfg.add_field(make_asn1_enum_number_str_parser("resources", &phichcfg.phich_res)); - parser::parse_section(args_->enb_files.rr_config, &phy_cnfg); - - cell->phich_length = (srslte_phich_length_t)(int)phichcfg.phich_dur; - cell->phich_resources = (srslte_phich_r_t)(int)phichcfg.phich_res; - - if (!srslte_cell_isvalid(cell)) { - fprintf(stderr, "Invalid cell parameters: nof_prb=%d, cell_id=%d\n", args_->enb.n_prb, args_->stack.s1ap.cell_id); - return -1; + for (uint32_t i = 0; i < l.size(); i++) { + for (uint32_t j = 0; j < l[i].sib_map_info.size(); j++) { + if (l[i].sib_map_info[j] == sib_num) { + return true; + } + } } - - return 0; + return false; } int field_sched_info::parse(libconfig::Setting& root) @@ -233,26 +219,6 @@ int field_carrier_freqs_info_list::parse(libconfig::Setting& root) return 0; } -int enb::parse_sib1(std::string filename, sib_type1_s* data) -{ - parser::section sib1("sib1"); - - sib1.add_field(make_asn1_enum_str_parser("intra_freq_reselection", &data->cell_access_related_info.intra_freq_resel)); - sib1.add_field(new parser::field("q_rx_lev_min", &data->cell_sel_info.q_rx_lev_min)); - sib1.add_field(new parser::field("p_max", &data->p_max, &data->p_max_present)); - sib1.add_field(make_asn1_enum_str_parser("cell_barred", &data->cell_access_related_info.cell_barred)); - sib1.add_field(make_asn1_enum_number_parser("si_window_length", &data->si_win_len)); - sib1.add_field(new parser::field("system_info_value_tag", &data->sys_info_value_tag)); - - // sched_info subsection uses a custom field class - parser::section sched_info("sched_info"); - sib1.add_subsection(&sched_info); - sched_info.add_field(new field_sched_info(data)); - - // Run parser with single section - return parser::parse_section(std::move(filename), &sib1); -} - bool extract_sf_alloc(mbsfn_sf_cfg_s::sf_alloc_c_* store_ptr, const char* name, Setting& root) { uint32_t alloc; @@ -312,960 +278,1120 @@ int mbsfn_sf_cfg_list_parser::parse(Setting& root) return 0; } -int enb::parse_sib2(std::string filename, sib_type2_s* data) +int mbsfn_area_info_list_parser::parse(Setting& root) { - parser::section sib2("sib2"); + if (not root.exists("mbsfn_area_info_list")) { + if (enabled) { + *enabled = false; + } + mbsfn_list->resize(0); + return 0; + } - sib2.add_field(make_asn1_enum_str_parser("time_alignment_timer", &data->time_align_timer_common)); - sib2.add_field(new mbsfn_sf_cfg_list_parser(&data->mbsfn_sf_cfg_list, &data->mbsfn_sf_cfg_list_present)); + mbsfn_list->resize(1); + if (enabled) { + *enabled = true; + } + mbsfn_area_info_r9_s* mbsfn_item = &(*mbsfn_list)[0]; - parser::section freqinfo("freqInfo"); - sib2.add_subsection(&freqinfo); - freqinfo.add_field(new parser::field("additional_spectrum_emission", &data->freq_info.add_spec_emission)); - freqinfo.add_field(new parser::field("ul_carrier_freq_present", &data->freq_info.ul_carrier_freq_present)); - freqinfo.add_field(new parser::field("ul_bw_present", &data->freq_info.ul_bw_present)); + field_asn1_enum_str fieldlen("non_mbsfn_region_length", + &mbsfn_item->non_mbsfn_region_len); + if (fieldlen.parse(root["mbsfn_area_info_list"])) { + fprintf(stderr, "Error parsing non_mbsfn_region_length\n"); + return -1; + } - // AC barring configuration - parser::section acbarring("ac_barring"); - sib2.add_subsection(&acbarring); - acbarring.set_optional(&data->ac_barr_info_present); + field_asn1_enum_str repeat( + "mcch_repetition_period", &mbsfn_item->mcch_cfg_r9.mcch_repeat_period_r9); + if (repeat.parse(root["mbsfn_area_info_list"])) { + fprintf(stderr, "Error parsing mcch_repetition_period\n"); + return -1; + } - acbarring.add_field(new parser::field("ac_barring_for_emergency", &data->ac_barr_info.ac_barr_for_emergency)); + field_asn1_enum_str mod( + "mcch_modification_period", &mbsfn_item->mcch_cfg_r9.mcch_mod_period_r9); + if (mod.parse(root["mbsfn_area_info_list"])) { + fprintf(stderr, "Error parsing mcch_modification_period\n"); + return -1; + } - parser::section acbarring_signalling("ac_barring_for_mo_signalling"); - acbarring.add_subsection(&acbarring_signalling); - acbarring_signalling.set_optional(&data->ac_barr_info.ac_barr_for_mo_sig_present); + field_asn1_enum_str sig("signalling_mcs", + &mbsfn_item->mcch_cfg_r9.sig_mcs_r9); + if (sig.parse(root["mbsfn_area_info_list"])) { + fprintf(stderr, "Error parsing signalling_mcs\n"); + return -1; + } - acbarring_signalling.add_field( - make_asn1_enum_number_str_parser("factor", &data->ac_barr_info.ac_barr_for_mo_sig.ac_barr_factor)); - acbarring_signalling.add_field( - make_asn1_enum_number_parser("time", &data->ac_barr_info.ac_barr_for_mo_sig.ac_barr_time)); - acbarring_signalling.add_field(make_asn1_bitstring_number_parser( - "for_special_ac", &data->ac_barr_info.ac_barr_for_mo_sig.ac_barr_for_special_ac)); + parser::field areaid("mbsfn_area_id", &mbsfn_item->mbsfn_area_id_r9); + if (areaid.parse(root["mbsfn_area_info_list"])) { + fprintf(stderr, "Error parsing mbsfn_area_id\n"); + return -1; + } - parser::section acbarring_data("ac_barring_for_mo_data"); - acbarring.add_subsection(&acbarring_data); - acbarring_data.set_optional(&data->ac_barr_info.ac_barr_for_mo_data_present); + parser::field notif_ind("notification_indicator", &mbsfn_item->notif_ind_r9); + if (notif_ind.parse(root["mbsfn_area_info_list"])) { + fprintf(stderr, "Error parsing notification_indicator\n"); + return -1; + } - acbarring_data.add_field( - make_asn1_enum_number_str_parser("factor", &data->ac_barr_info.ac_barr_for_mo_data.ac_barr_factor)); - acbarring_data.add_field(make_asn1_enum_number_parser("fime", &data->ac_barr_info.ac_barr_for_mo_data.ac_barr_time)); - acbarring_data.add_field(make_asn1_bitstring_number_parser( - "for_special_ac", &data->ac_barr_info.ac_barr_for_mo_data.ac_barr_for_special_ac)); + parser::field offset("mcch_offset", &mbsfn_item->mcch_cfg_r9.mcch_offset_r9); + if (offset.parse(root["mbsfn_area_info_list"])) { + fprintf(stderr, "Error parsing mcch_offset\n"); + return -1; + } - // UE timers and constants - parser::section uetimers("ue_timers_and_constants"); - sib2.add_subsection(&uetimers); - uetimers.add_field(make_asn1_enum_number_parser("t300", &data->ue_timers_and_consts.t300)); - uetimers.add_field(make_asn1_enum_number_parser("t301", &data->ue_timers_and_consts.t301)); - uetimers.add_field(make_asn1_enum_number_parser("t310", &data->ue_timers_and_consts.t310)); - uetimers.add_field(make_asn1_enum_number_parser("n310", &data->ue_timers_and_consts.n310)); - uetimers.add_field(make_asn1_enum_number_parser("t311", &data->ue_timers_and_consts.t311)); - uetimers.add_field(make_asn1_enum_number_parser("n311", &data->ue_timers_and_consts.n311)); + field_asn1_bitstring_number, uint8_t> alloc_info("sf_alloc_info", + &mbsfn_item->mcch_cfg_r9.sf_alloc_info_r9); + if (alloc_info.parse(root["mbsfn_area_info_list"])) { + fprintf(stderr, "Error parsing mbsfn_area_info_list\n"); + return -1; + } - // Radio-resource configuration section - parser::section rr_config("rr_config_common_sib"); - sib2.add_subsection(&rr_config); - rr_cfg_common_sib_s* rr_cfg_common = &data->rr_cfg_common; + return 0; +} - rr_config.add_field(make_asn1_enum_str_parser("ul_cp_length", &rr_cfg_common->ul_cp_len)); +int field_sf_mapping::parse(libconfig::Setting& root) +{ + *nof_subframes = root["subframe"].getLength(); + for (uint32_t i = 0; i < *nof_subframes; i++) { + sf_mapping[i] = root["subframe"][i]; + } + return 0; +} - // RACH configuration - parser::section rach_cnfg("rach_cnfg"); - rr_config.add_subsection(&rach_cnfg); +int phr_cnfg_parser::parse(libconfig::Setting& root) +{ + if (not root.exists("phr_cnfg")) { + phr_cfg->set(mac_main_cfg_s::phr_cfg_c_::types::release); + return 0; + } + phr_cfg->set_setup(); + mac_main_cfg_s::phr_cfg_c_::setup_s_& s = phr_cfg->setup(); - rach_cnfg.add_field( - make_asn1_enum_number_parser("num_ra_preambles", &rr_cfg_common->rach_cfg_common.preamb_info.nof_ra_preambs)); - rach_cnfg.add_field(make_asn1_enum_number_parser( - "preamble_init_rx_target_pwr", &rr_cfg_common->rach_cfg_common.pwr_ramp_params.preamb_init_rx_target_pwr)); - rach_cnfg.add_field( - make_asn1_enum_number_parser("pwr_ramping_step", &rr_cfg_common->rach_cfg_common.pwr_ramp_params.pwr_ramp_step)); - rach_cnfg.add_field(make_asn1_enum_number_parser( - "preamble_trans_max", &rr_cfg_common->rach_cfg_common.ra_supervision_info.preamb_trans_max)); - rach_cnfg.add_field(make_asn1_enum_number_parser( - "ra_resp_win_size", &rr_cfg_common->rach_cfg_common.ra_supervision_info.ra_resp_win_size)); - rach_cnfg.add_field(make_asn1_enum_number_parser( - "mac_con_res_timer", &rr_cfg_common->rach_cfg_common.ra_supervision_info.mac_contention_resolution_timer)); - rach_cnfg.add_field(new parser::field("max_harq_msg3_tx", &rr_cfg_common->rach_cfg_common.max_harq_msg3_tx)); + if (not parse_enum_by_str(s.dl_pathloss_change, "dl_pathloss_change", root["phr_cnfg"])) { + return -1; + } + if (not parse_enum_by_number(s.periodic_phr_timer, "periodic_phr_timer", root["phr_cnfg"])) { + return -1; + } + if (not parse_enum_by_number(s.prohibit_phr_timer, "prohibit_phr_timer", root["phr_cnfg"])) { + return -1; + } + return 0; +} - parser::section groupa_cnfg("preambles_group_a_cnfg"); - rach_cnfg.add_subsection(&groupa_cnfg); - groupa_cnfg.set_optional(&rr_cfg_common->rach_cfg_common.preamb_info.preambs_group_a_cfg_present); - rach_cfg_common_s::preamb_info_s_::preambs_group_a_cfg_s_* group_acfg = - &rr_cfg_common->rach_cfg_common.preamb_info.preambs_group_a_cfg; - groupa_cnfg.add_field(make_asn1_enum_number_parser("size_of_ra", &group_acfg->size_of_ra_preambs_group_a)); - groupa_cnfg.add_field(make_asn1_enum_number_parser("msg_size", &group_acfg->msg_size_group_a)); - groupa_cnfg.add_field(make_asn1_enum_number_parser("msg_pwr_offset_group_b", &group_acfg->msg_pwr_offset_group_b)); - // rr_cfg_common->rach_cfg_common.preamb_info.nof_ra_preambs = FIXME: ??? +int field_qci::parse(libconfig::Setting& root) +{ + auto nof_qci = (uint32_t)root.getLength(); - // BCCH configuration - parser::section bcch_cnfg("bcch_cnfg"); - rr_config.add_subsection(&bcch_cnfg); - bcch_cnfg.add_field( - make_asn1_enum_number_parser("modification_period_coeff", &rr_cfg_common->bcch_cfg.mod_period_coeff)); + for (uint32_t i = 0; i < MAX_NOF_QCI; i++) { + cfg->configured = false; + } - // PCCH configuration - parser::section pcch_cnfg("pcch_cnfg"); - rr_config.add_subsection(&pcch_cnfg); - pcch_cnfg.add_field( - make_asn1_enum_number_parser("default_paging_cycle", &rr_cfg_common->pcch_cfg.default_paging_cycle)); - pcch_cnfg.add_field(make_asn1_enum_number_str_parser("nB", &rr_cfg_common->pcch_cfg.nb)); + for (uint32_t i = 0; i < nof_qci; i++) { + libconfig::Setting& q = root[i]; - // PRACH configuration - parser::section prach_cnfg("prach_cnfg"); - rr_config.add_subsection(&prach_cnfg); - prach_cnfg.add_field(new parser::field("root_sequence_index", &rr_cfg_common->prach_cfg.root_seq_idx)); - parser::section prach_cnfg_info("prach_cnfg_info"); - prach_cnfg.add_subsection(&prach_cnfg_info); - prach_cnfg_info.add_field( - new parser::field("high_speed_flag", &rr_cfg_common->prach_cfg.prach_cfg_info.high_speed_flag)); - prach_cnfg_info.add_field( - new parser::field("prach_config_index", &rr_cfg_common->prach_cfg.prach_cfg_info.prach_cfg_idx)); - prach_cnfg_info.add_field( - new parser::field("prach_freq_offset", &rr_cfg_common->prach_cfg.prach_cfg_info.prach_freq_offset)); - prach_cnfg_info.add_field(new parser::field( - "zero_correlation_zone_config", &rr_cfg_common->prach_cfg.prach_cfg_info.zero_correlation_zone_cfg)); + uint32_t qci = q["qci"]; - // PDSCH configuration - parser::section pdsch_cnfg("pdsch_cnfg"); - rr_config.add_subsection(&pdsch_cnfg); - pdsch_cnfg.add_field(new parser::field("p_b", &rr_cfg_common->pdsch_cfg_common.p_b)); - pdsch_cnfg.add_field(new parser::field("rs_power", &rr_cfg_common->pdsch_cfg_common.ref_sig_pwr)); + // Parse PDCP section + if (!q.exists("pdcp_config")) { + fprintf(stderr, "Error section pdcp_config not found for qci=%d\n", qci); + return -1; + } - // PUSCH configuration - parser::section pusch_cnfg("pusch_cnfg"); - rr_config.add_subsection(&pusch_cnfg); - pusch_cnfg.add_field(new parser::field("n_sb", &rr_cfg_common->pusch_cfg_common.pusch_cfg_basic.n_sb)); - pusch_cnfg.add_field( - make_asn1_enum_str_parser("hopping_mode", &rr_cfg_common->pusch_cfg_common.pusch_cfg_basic.hop_mode)); - pusch_cnfg.add_field(new parser::field("pusch_hopping_offset", - &rr_cfg_common->pusch_cfg_common.pusch_cfg_basic.pusch_hop_offset)); - pusch_cnfg.add_field( - new parser::field("enable_64_qam", &rr_cfg_common->pusch_cfg_common.pusch_cfg_basic.enable64_qam)); + field_asn1_enum_number discard_timer( + "discard_timer", &cfg[qci].pdcp_cfg.discard_timer, &cfg[qci].pdcp_cfg.discard_timer_present); + discard_timer.parse(q["pdcp_config"]); - // PUSCH-ULRS configuration - parser::section ulrs_cnfg("ul_rs"); - pusch_cnfg.add_subsection(&ulrs_cnfg); - ulrs_cnfg.add_field( - new parser::field("cyclic_shift", &rr_cfg_common->pusch_cfg_common.ul_ref_sigs_pusch.cyclic_shift)); - ulrs_cnfg.add_field(new parser::field("group_assignment_pusch", - &rr_cfg_common->pusch_cfg_common.ul_ref_sigs_pusch.group_assign_pusch)); - ulrs_cnfg.add_field(new parser::field("group_hopping_enabled", - &rr_cfg_common->pusch_cfg_common.ul_ref_sigs_pusch.group_hop_enabled)); - ulrs_cnfg.add_field(new parser::field("sequence_hopping_enabled", - &rr_cfg_common->pusch_cfg_common.ul_ref_sigs_pusch.seq_hop_enabled)); + field_asn1_enum_number pdcp_sn_size( + "pdcp_sn_size", &cfg[qci].pdcp_cfg.rlc_um.pdcp_sn_size, &cfg[qci].pdcp_cfg.rlc_um_present); + pdcp_sn_size.parse(q["pdcp_config"]); - // PUCCH configuration - parser::section pucch_cnfg("pucch_cnfg"); - rr_config.add_subsection(&pucch_cnfg); - pucch_cnfg.add_field( - make_asn1_enum_number_parser("delta_pucch_shift", &rr_cfg_common->pucch_cfg_common.delta_pucch_shift)); - pucch_cnfg.add_field(new parser::field("n_rb_cqi", &rr_cfg_common->pucch_cfg_common.n_rb_cqi)); - pucch_cnfg.add_field(new parser::field("n_cs_an", &rr_cfg_common->pucch_cfg_common.n_cs_an)); - pucch_cnfg.add_field(new parser::field("n1_pucch_an", &rr_cfg_common->pucch_cfg_common.n1_pucch_an)); + cfg[qci].pdcp_cfg.rlc_am_present = + q["pdcp_config"].lookupValue("status_report_required", cfg[qci].pdcp_cfg.rlc_am.status_report_required); + cfg[qci].pdcp_cfg.hdr_compress.set(pdcp_cfg_s::hdr_compress_c_::types::not_used); - // UL PWR Ctrl configuration - parser::section ul_pwr_ctrl("ul_pwr_ctrl"); - rr_config.add_subsection(&ul_pwr_ctrl); - ul_pwr_ctrl.add_field( - new parser::field("p0_nominal_pusch", &rr_cfg_common->ul_pwr_ctrl_common.p0_nominal_pusch)); - ul_pwr_ctrl.add_field(make_asn1_enum_number_parser("alpha", &rr_cfg_common->ul_pwr_ctrl_common.alpha)); - ul_pwr_ctrl.add_field( - new parser::field("p0_nominal_pucch", &rr_cfg_common->ul_pwr_ctrl_common.p0_nominal_pucch)); - ul_pwr_ctrl.add_field( - new parser::field("delta_preamble_msg3", &rr_cfg_common->ul_pwr_ctrl_common.delta_preamb_msg3)); + // Parse RLC section + rlc_cfg_c* rlc_cfg = &cfg[qci].rlc_cfg; + if (q["rlc_config"].exists("ul_am")) { + rlc_cfg->set_am(); + } else if (q["rlc_config"].exists("ul_um") && q["rlc_config"].exists("dl_um")) { + rlc_cfg->set_um_bi_dir(); + } else if (q["rlc_config"].exists("ul_um") && !q["rlc_config"].exists("dl_um")) { + rlc_cfg->set_um_uni_dir_ul(); + } else if (!q["rlc_config"].exists("ul_um") && q["rlc_config"].exists("dl_um")) { + rlc_cfg->set_um_uni_dir_dl(); + } else { + fprintf(stderr, "Invalid combination of UL/DL UM/AM for qci=%d\n", qci); + return -1; + } - // Delta Flist PUCCH - parser::section delta_flist("delta_flist_pucch"); - ul_pwr_ctrl.add_subsection(&delta_flist); - delta_flist.add_field(make_asn1_enum_number_parser( - "format_1", &rr_cfg_common->ul_pwr_ctrl_common.delta_flist_pucch.delta_f_pucch_format1)); - delta_flist.add_field(make_asn1_enum_number_parser( - "format_1b", &rr_cfg_common->ul_pwr_ctrl_common.delta_flist_pucch.delta_f_pucch_format1b)); - delta_flist.add_field(make_asn1_enum_number_parser( - "format_2", &rr_cfg_common->ul_pwr_ctrl_common.delta_flist_pucch.delta_f_pucch_format2)); - delta_flist.add_field(make_asn1_enum_number_parser( - "format_2a", &rr_cfg_common->ul_pwr_ctrl_common.delta_flist_pucch.delta_f_pucch_format2a)); - delta_flist.add_field(make_asn1_enum_number_parser( - "format_2b", &rr_cfg_common->ul_pwr_ctrl_common.delta_flist_pucch.delta_f_pucch_format2b)); + // Parse RLC-UM section + if (q["rlc_config"].exists("ul_um")) { - // Run parser with single section - return parser::parse_section(std::move(filename), &sib2); -} + ul_um_rlc_s* um_rlc; + if (rlc_cfg->type() == rlc_cfg_c::types::um_uni_dir_ul) { + um_rlc = &rlc_cfg->um_uni_dir_ul().ul_um_rlc; + } else { + um_rlc = &rlc_cfg->um_bi_dir().ul_um_rlc; + } -int enb::parse_sib3(std::string filename, sib_type3_s* data) -{ - parser::section sib3("sib3"); + field_asn1_enum_number sn_field_len("sn_field_length", &um_rlc->sn_field_len); + if (sn_field_len.parse(q["rlc_config"]["ul_um"])) { + ERROR("Error can't find sn_field_length in section ul_um\n"); + } + } - // CellReselectionInfoCommon - parser::section resel_common("cell_reselection_common"); - sib3.add_subsection(&resel_common); + if (q["rlc_config"].exists("dl_um")) { - resel_common.add_field(make_asn1_enum_number_parser("q_hyst", &data->cell_resel_info_common.q_hyst)); + dl_um_rlc_s* um_rlc; + if (rlc_cfg->type() == rlc_cfg_c::types::um_uni_dir_dl) { + um_rlc = &rlc_cfg->um_uni_dir_dl().dl_um_rlc; + } else { + um_rlc = &rlc_cfg->um_bi_dir().dl_um_rlc; + } - parser::section speed_resel("speed_state_resel_params"); - resel_common.add_subsection(&speed_resel); - resel_common.set_optional(&data->cell_resel_info_common.speed_state_resel_pars_present); - sib_type3_s::cell_resel_info_common_s_::speed_state_resel_pars_s_* resel_pars = - &data->cell_resel_info_common.speed_state_resel_pars; + field_asn1_enum_number sn_field_len("sn_field_length", &um_rlc->sn_field_len); + if (sn_field_len.parse(q["rlc_config"]["dl_um"])) { + ERROR("Error can't find sn_field_length in section dl_um\n"); + } - parser::section q_hyst_sf("q_hyst_sf"); - speed_resel.add_subsection(&q_hyst_sf); - q_hyst_sf.add_field(make_asn1_enum_number_parser("medium", &resel_pars->q_hyst_sf.sf_medium)); - q_hyst_sf.add_field(make_asn1_enum_number_parser("high", &resel_pars->q_hyst_sf.sf_high)); + field_asn1_enum_number t_reordering("t_reordering", &um_rlc->t_reordering); + if (t_reordering.parse(q["rlc_config"]["dl_um"])) { + ERROR("Error can't find t_reordering in section dl_um\n"); + } + } - parser::section mob_params("mobility_state_params"); - speed_resel.add_subsection(&mob_params); - mob_params.add_field(make_asn1_enum_number_parser("t_eval", &resel_pars->mob_state_params.t_eval)); - mob_params.add_field(make_asn1_enum_number_parser("t_hyst_normal", &resel_pars->mob_state_params.t_hyst_normal)); - mob_params.add_field( - new parser::field("n_cell_change_medium", &resel_pars->mob_state_params.n_cell_change_medium)); - mob_params.add_field( - new parser::field("n_cell_change_high", &resel_pars->mob_state_params.n_cell_change_high)); + // Parse RLC-AM section + if (q["rlc_config"].exists("ul_am")) { + ul_am_rlc_s* am_rlc = &rlc_cfg->am().ul_am_rlc; - // CellReselectionServingFreqInfo - parser::section resel_serving("cell_reselection_serving"); - sib3.add_subsection(&resel_serving); - sib_type3_s::cell_resel_serving_freq_info_s_* freqinfo = &data->cell_resel_serving_freq_info; + field_asn1_enum_number t_poll_retx("t_poll_retx", &am_rlc->t_poll_retx); + if (t_poll_retx.parse(q["rlc_config"]["ul_am"])) { + ERROR("Error can't find t_poll_retx in section ul_am\n"); + } - resel_serving.add_field(new parser::field( - "s_non_intra_search", &freqinfo->s_non_intra_search, &freqinfo->s_non_intra_search_present)); - resel_serving.add_field(new parser::field("thresh_serving_low", &freqinfo->thresh_serving_low)); - resel_serving.add_field(new parser::field("cell_resel_prio", &freqinfo->cell_resel_prio)); + field_asn1_enum_number poll_pdu("poll_pdu", &am_rlc->poll_pdu); + if (poll_pdu.parse(q["rlc_config"]["ul_am"])) { + ERROR("Error can't find poll_pdu in section ul_am\n"); + } - // intraFreqCellReselectionInfo - parser::section intra_freq("intra_freq_reselection"); - sib3.add_subsection(&intra_freq); - sib_type3_s::intra_freq_cell_resel_info_s_* intrafreq = &data->intra_freq_cell_resel_info; + field_asn1_enum_number poll_byte("poll_byte", &am_rlc->poll_byte); + if (poll_byte.parse(q["rlc_config"]["ul_am"])) { + ERROR("Error can't find poll_byte in section ul_am\n"); + } - intra_freq.add_field(new parser::field("q_rx_lev_min", &intrafreq->q_rx_lev_min)); - intra_freq.add_field(new parser::field("p_max", &intrafreq->p_max, &intrafreq->p_max_present)); - intra_freq.add_field( - new parser::field("s_intra_search", &intrafreq->s_intra_search, &intrafreq->s_intra_search_present)); - intra_freq.add_field(make_asn1_enum_number_parser( - "allowed_meas_bw", &intrafreq->allowed_meas_bw, &intrafreq->allowed_meas_bw_present)); - intra_freq.add_field(new parser::field("presence_ant_port_1", &intrafreq->presence_ant_port1)); - intra_freq.add_field(make_asn1_bitstring_number_parser("neigh_cell_cnfg", &intrafreq->neigh_cell_cfg)); - intra_freq.add_field(new parser::field("t_resel_eutra", &intrafreq->t_resel_eutra)); + field_asn1_enum_number max_retx_thresh("max_retx_thresh", + &am_rlc->max_retx_thres); + if (max_retx_thresh.parse(q["rlc_config"]["ul_am"])) { + ERROR("Error can't find max_retx_thresh in section ul_am\n"); + } + } - parser::section t_resel_eutra_sf("t_resel_eutra_sf"); - intra_freq.add_subsection(&t_resel_eutra_sf); - t_resel_eutra_sf.set_optional(&intrafreq->t_resel_eutra_sf_present); + if (q["rlc_config"].exists("dl_am")) { + dl_am_rlc_s* am_rlc = &rlc_cfg->am().dl_am_rlc; - t_resel_eutra_sf.add_field(make_asn1_enum_number_str_parser("sf_medium", &intrafreq->t_resel_eutra_sf.sf_medium)); - t_resel_eutra_sf.add_field(make_asn1_enum_number_str_parser("sf_high", &intrafreq->t_resel_eutra_sf.sf_high)); + field_asn1_enum_number t_reordering("t_reordering", &am_rlc->t_reordering); + if (t_reordering.parse(q["rlc_config"]["dl_am"])) { + ERROR("Error can't find t_reordering in section dl_am\n"); + } - // Run parser with single section - return parser::parse_section(std::move(filename), &sib3); -} + field_asn1_enum_number t_status_prohibit("t_status_prohibit", &am_rlc->t_status_prohibit); + if (t_status_prohibit.parse(q["rlc_config"]["dl_am"])) { + ERROR("Error can't find t_status_prohibit in section dl_am\n"); + } + } -int enb::parse_sib4(std::string filename, sib_type4_s* data) -{ - parser::section sib4("sib4"); + // Parse logical channel configuration section + if (!q.exists("logical_channel_config")) { + fprintf(stderr, "Error section logical_channel_config not found for qci=%d\n", qci); + return -1; + } - // csg-PhysCellIdRange - parser::section csg_range("csg_phys_cell_id_range"); - sib4.add_subsection(&csg_range); - csg_range.set_optional(&data->csg_pci_range_present); - csg_range.add_field(make_asn1_enum_number_parser("range", &data->csg_pci_range.range)); - csg_range.add_field(new parser::field("start", &data->csg_pci_range.start)); + lc_ch_cfg_s::ul_specific_params_s_* lc_cfg = &cfg[qci].lc_cfg; - // intraFreqNeighCellList - parser::section intra_neigh("intra_freq_neigh_cell_list"); - sib4.add_subsection(&intra_neigh); - bool dummy_bool = false; - intra_neigh.set_optional(&dummy_bool); - intra_neigh.add_field(new field_intra_neigh_cell_list(data)); + parser::field priority("priority", &lc_cfg->prio); + if (priority.parse(q["logical_channel_config"])) { + ERROR("Error can't find logical_channel_config in section priority\n"); + } - // intraFreqBlackCellList - parser::section intra_black("intra_freq_black_cell_list"); - sib4.add_subsection(&intra_black); - intra_black.set_optional(&dummy_bool); - intra_black.add_field(new field_intra_black_cell_list(data)); + field_asn1_enum_number prioritised_bit_rate( + "prioritized_bit_rate", &lc_cfg->prioritised_bit_rate); + if (prioritised_bit_rate.parse(q["logical_channel_config"])) { + fprintf(stderr, "Error can't find prioritized_bit_rate in section logical_channel_config\n"); + } - // Run parser with single section - return parser::parse_section(std::move(filename), &sib4); + field_asn1_enum_number bucket_size_duration( + "bucket_size_duration", &lc_cfg->bucket_size_dur); + if (bucket_size_duration.parse(q["logical_channel_config"])) { + ERROR("Error can't find bucket_size_duration in section logical_channel_config\n"); + } + + parser::field log_chan_group("log_chan_group", &lc_cfg->lc_ch_group); + lc_cfg->lc_ch_group_present = not log_chan_group.parse(q["logical_channel_config"]); + cfg[qci].configured = true; + } + + return 0; } -int enb::parse_sib7(std::string filename, sib_type7_s* data) +namespace rr_sections { + +int parse_rr(all_args_t* args_, rrc_cfg_t* rrc_cfg_) { - parser::section sib7("sib7"); + /* Transmission mode config section */ + if (args_->enb.transmission_mode < 1 || args_->enb.transmission_mode > 4) { + ERROR("Invalid transmission mode (%d). Only indexes 1-4 are implemented.\n", args_->enb.transmission_mode); + return SRSLTE_ERROR; + } else if (args_->enb.transmission_mode == 1 && args_->enb.nof_ports > 1) { + ERROR("Invalid number of ports (%d) for transmission mode (%d). Only one antenna port is allowed.\n", + args_->enb.nof_ports, + args_->enb.transmission_mode); + return SRSLTE_ERROR; + } else if (args_->enb.transmission_mode > 1 && args_->enb.nof_ports != 2) { + ERROR("The selected number of ports (%d) are insufficient for the selected transmission mode (%d).\n", + args_->enb.nof_ports, + args_->enb.transmission_mode); + return SRSLTE_ERROR; + } - sib7.add_field(new parser::field("t_resel_geran", &data->t_resel_geran)); - // TODO: t_resel_geran_sf + rrc_cfg_->antenna_info.tx_mode = (ant_info_ded_s::tx_mode_e_::options)(args_->enb.transmission_mode - 1); - data->carrier_freqs_info_list_present = true; - parser::section geran_neigh("carrier_freqs_info_list"); - sib7.add_subsection(&geran_neigh); + rrc_cfg_->antenna_info.ue_tx_ant_sel.set_setup(); + switch (rrc_cfg_->antenna_info.tx_mode) { + case ant_info_ded_s::tx_mode_e_::tm1: + case ant_info_ded_s::tx_mode_e_::tm2: + rrc_cfg_->antenna_info.ue_tx_ant_sel.set(setup_e::release); + rrc_cfg_->antenna_info.codebook_subset_restrict_present = false; + break; + case ant_info_ded_s::tx_mode_e_::tm3: + rrc_cfg_->antenna_info.ue_tx_ant_sel.setup().value = ant_info_ded_s::ue_tx_ant_sel_c_::setup_e_::open_loop; - bool dummy_bool = false; - geran_neigh.set_optional(&dummy_bool); - geran_neigh.add_field(new field_carrier_freqs_info_list(data)); + rrc_cfg_->antenna_info.codebook_subset_restrict_present = true; + rrc_cfg_->antenna_info.codebook_subset_restrict.set_n2_tx_ant_tm3(); + rrc_cfg_->antenna_info.codebook_subset_restrict.n2_tx_ant_tm3().from_number(0b11); + break; + case ant_info_ded_s::tx_mode_e_::tm4: + rrc_cfg_->antenna_info.ue_tx_ant_sel.setup().value = ant_info_ded_s::ue_tx_ant_sel_c_::setup_e_::closed_loop; + + rrc_cfg_->antenna_info.codebook_subset_restrict_present = true; + rrc_cfg_->antenna_info.codebook_subset_restrict.set_n2_tx_ant_tm4(); + rrc_cfg_->antenna_info.codebook_subset_restrict.n2_tx_ant_tm4().from_number(0b111111); + break; + default: + ERROR("Unsupported transmission mode %d\n", rrc_cfg_->antenna_info.tx_mode.to_number()); + return SRSLTE_ERROR; + } + + /* Parse power allocation */ + if (not asn1::number_to_enum(rrc_cfg_->pdsch_cfg, args_->enb.p_a)) { + ERROR("Invalid p_a value (%f) only -6, -4.77, -3, -1.77, 0, 1, 2, 3 values allowed.", args_->enb.p_a); + return SRSLTE_ERROR; + } + + /* MAC config section */ + parser::section mac_cnfg("mac_cnfg"); + parser::section phr_cnfg("phr_cnfg"); + mac_cnfg.add_subsection(&phr_cnfg); + rrc_cfg_->mac_cnfg.phr_cfg.set( + mac_main_cfg_s::phr_cfg_c_::types::release); // default is release if "phr_cnfg" is not found + mac_cnfg.add_field(new phr_cnfg_parser(&rrc_cfg_->mac_cnfg.phr_cfg)); + // mac_cnfg.add_field(new phr_cnfg_parser(&rrc_cfg_->mac_cnfg.phr_cfg)); + + parser::section ulsch_cnfg("ulsch_cnfg"); + mac_cnfg.add_subsection(&ulsch_cnfg); + + rrc_cfg_->mac_cnfg.ul_sch_cfg.tti_bundling = false; + ulsch_cnfg.add_field(make_asn1_enum_number_parser( + "max_harq_tx", &rrc_cfg_->mac_cnfg.ul_sch_cfg.max_harq_tx, &rrc_cfg_->mac_cnfg.ul_sch_cfg.max_harq_tx_present)); + ulsch_cnfg.add_field(make_asn1_enum_number_parser("periodic_bsr_timer", + &rrc_cfg_->mac_cnfg.ul_sch_cfg.periodic_bsr_timer, + &rrc_cfg_->mac_cnfg.ul_sch_cfg.periodic_bsr_timer_present)); + ulsch_cnfg.add_field(make_asn1_enum_number_parser("retx_bsr_timer", &rrc_cfg_->mac_cnfg.ul_sch_cfg.retx_bsr_timer)); + + mac_cnfg.add_field(make_asn1_enum_number_parser("time_alignment_timer", &rrc_cfg_->mac_cnfg.time_align_timer_ded)); + + /* PHY config section */ + parser::section phy_cfg_("phy_cnfg"); + + parser::section pusch_cnfg_ded("pusch_cnfg_ded"); + phy_cfg_.add_subsection(&pusch_cnfg_ded); + + pusch_cnfg_ded.add_field(new parser::field("beta_offset_ack_idx", &rrc_cfg_->pusch_cfg.beta_offset_ack_idx)); + pusch_cnfg_ded.add_field(new parser::field("beta_offset_ri_idx", &rrc_cfg_->pusch_cfg.beta_offset_ri_idx)); + pusch_cnfg_ded.add_field(new parser::field("beta_offset_cqi_idx", &rrc_cfg_->pusch_cfg.beta_offset_cqi_idx)); + + parser::section sched_request_cnfg("sched_request_cnfg"); + phy_cfg_.add_subsection(&sched_request_cnfg); + + sched_request_cnfg.add_field(make_asn1_enum_number_parser("dsr_trans_max", &rrc_cfg_->sr_cfg.dsr_max)); + sched_request_cnfg.add_field(new parser::field("period", &rrc_cfg_->sr_cfg.period)); + sched_request_cnfg.add_field(new parser::field("nof_prb", &rrc_cfg_->sr_cfg.nof_prb)); + sched_request_cnfg.add_field(new field_sf_mapping(rrc_cfg_->sr_cfg.sf_mapping, &rrc_cfg_->sr_cfg.nof_subframes)); + + parser::section cqi_report_cnfg("cqi_report_cnfg"); + phy_cfg_.add_subsection(&cqi_report_cnfg); + + cqi_report_cnfg.add_field(new parser::field_enum_str( + "mode", &rrc_cfg_->cqi_cfg.mode, rrc_cfg_cqi_mode_text, RRC_CFG_CQI_MODE_N_ITEMS)); + cqi_report_cnfg.add_field(new parser::field("period", &rrc_cfg_->cqi_cfg.period)); + cqi_report_cnfg.add_field(new parser::field("m_ri", &rrc_cfg_->cqi_cfg.m_ri)); + cqi_report_cnfg.add_field(new parser::field("nof_prb", &rrc_cfg_->cqi_cfg.nof_prb)); + cqi_report_cnfg.add_field(new parser::field("simultaneousAckCQI", &rrc_cfg_->cqi_cfg.simultaneousAckCQI)); + cqi_report_cnfg.add_field(new field_sf_mapping(rrc_cfg_->cqi_cfg.sf_mapping, &rrc_cfg_->cqi_cfg.nof_subframes)); + + /* RRC config section */ + parser::section rrc_cnfg("cell_list"); + rrc_cnfg.set_optional(&rrc_cfg_->meas_cfg_present); + rrc_cnfg.add_field(new rr_sections::cell_list_section(args_, rrc_cfg_)); - return parser::parse_section(std::move(filename), &sib7); + // Run parser with two sections + parser p(args_->enb_files.rr_config); + p.add_section(&mac_cnfg); + p.add_section(&phy_cfg_); + p.add_section(&rrc_cnfg); + return p.parse(); } -int enb::parse_sib9(std::string filename, sib_type9_s* data) +static int parse_meas_cell_list(rrc_meas_cfg_t* meas_cfg, Setting& root) { - parser::section sib9("sib9"); - - bool name_enabled, hex_enabled; - std::string hnb_name, hex_value; - - sib9.add_field(new parser::field("hnb_name", &hnb_name, &name_enabled)); - sib9.add_field(new parser::field("hex_value", &hex_value, &hex_enabled)); - - // Run parser with single section - if (!parser::parse_section(std::move(filename), &sib9)) { - data->hnb_name_present = true; - if (name_enabled) { - data->hnb_name.resize(SRSLTE_MIN((uint32_t)hnb_name.size(), 48)); - memcpy(data->hnb_name.data(), hnb_name.c_str(), data->hnb_name.size()); - } else if (hex_enabled) { - if (hex_value.size() > 48) { - hex_value.resize(48); - } - data->hnb_name.from_string(hex_value); - } else { - data->hnb_name_present = false; - } - return 0; - } else { - return -1; + meas_cfg->meas_cells.resize(root.getLength()); + for (uint32_t i = 0; i < meas_cfg->meas_cells.size(); ++i) { + meas_cfg->meas_cells[i].earfcn = root[i]["dl_earfcn"]; + meas_cfg->meas_cells[i].pci = (unsigned int)root[i]["pci"] % 504; + meas_cfg->meas_cells[i].eci = (unsigned int)root[i]["eci"]; + meas_cfg->meas_cells[i].q_offset = 0; // LIBLTE_RRC_Q_OFFSET_RANGE_DB_0; // TODO + // // FIXME: TEMP + // printf("PARSER: neighbor cell: {dl_earfcn=%d pci=%d cell_idx=0x%x}\n", + // meas_cfg->meas_cells[i].earfcn, + // meas_cfg->meas_cells[i].pci, + // meas_cfg->meas_cells[i].eci); } + return 0; } -int enb::parse_sib13(std::string filename, sib_type13_r9_s* data) +static int parse_meas_report_desc(rrc_meas_cfg_t* meas_cfg, Setting& root) { - parser::section sib13("sib13"); - - sib13.add_field(make_asn1_seqof_size_parser("mbsfn_area_info_list_size", &data->mbsfn_area_info_list_r9)); + // NOTE: For now, only support one meas_report for all cells. + // TODO: for a1 + // TODO: for a2 + // meas report parsing + meas_cfg->meas_reports.resize(1); + asn1::rrc::report_cfg_eutra_s& meas_item = meas_cfg->meas_reports[0]; + HANDLEPARSERCODE(asn1_parsers::str_to_enum(meas_item.trigger_quant, root["a3_report_type"])); + auto& event = meas_item.trigger_type.set_event(); + event.event_id.set_event_a3().report_on_leave = false; + event.event_id.event_a3().a3_offset = (int)root["a3_offset"]; + event.hysteresis = (int)root["a3_hysteresis"]; + meas_item.max_report_cells = 1; // TODO: parse + meas_item.report_amount.value = report_cfg_eutra_s::report_amount_e_::r1; // TODO: parse + meas_item.report_interv.value = report_interv_e::ms120; // TODO: parse + meas_item.report_quant.value = report_cfg_eutra_s::report_quant_opts::both; // TODO: parse + // quant coeff parsing + auto& quant = meas_cfg->quant_cfg; + HANDLEPARSERCODE(asn1_parsers::number_to_enum(event.time_to_trigger, root["a3_time_to_trigger"])); + HANDLEPARSERCODE( + asn1_parsers::opt_number_to_enum(quant.filt_coef_rsrp, quant.filt_coef_rsrp_present, root, "rsrp_config")); + HANDLEPARSERCODE( + asn1_parsers::opt_number_to_enum(quant.filt_coef_rsrq, quant.filt_coef_rsrq_present, root, "rsrq_config")); - parser::section mbsfn_notification_config("mbsfn_notification_config"); - sib13.add_subsection(&mbsfn_notification_config); + return SRSLTE_SUCCESS; +} - mbsfn_notification_config.add_field( - make_asn1_enum_str_parser("mbsfn_notification_repetition_coeff", &data->notif_cfg_r9.notif_repeat_coeff_r9)); +static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root) +{ + auto cell_id_parser = [](uint32_t& cell_id, Setting& root) { return parse_bounded_number(cell_id, root, 0u, 255u); }; + uint32_t self_cellid = args->stack.s1ap.cell_id & 0xFFu; - mbsfn_notification_config.add_field( - new parser::field("mbsfn_notification_offset", &data->notif_cfg_r9.notif_offset_r9)); + rrc_cfg->cell_list.resize(root.getLength()); + for (uint32_t n = 0; n < rrc_cfg->cell_list.size(); ++n) { + cell_cfg_t& cell_cfg = rrc_cfg->cell_list[n]; + auto& cellroot = root[n]; - mbsfn_notification_config.add_field( - new parser::field("mbsfn_notification_sf_index", &data->notif_cfg_r9.notif_sf_idx_r9)); + parse_opt_field(cell_cfg.rf_port, cellroot, "rf_port"); + parse_default_field(cell_cfg.cell_id, cellroot, "cell_id", self_cellid, cell_id_parser); + parse_default_field(cell_cfg.tac, cellroot, "tac", args->stack.s1ap.tac); + parse_default_field(cell_cfg.pci, cellroot, "pci", args->enb.pci); + parse_default_field( + cell_cfg.root_seq_idx, cellroot, "root_seq_idx", rrc_cfg->sibs[1].sib2().rr_cfg_common.prach_cfg.root_seq_idx); + parse_default_field(cell_cfg.dl_earfcn, cellroot, "dl_earfcn", args->enb.dl_earfcn); + parse_default_field(cell_cfg.ul_earfcn, cellroot, "ul_earfcn", args->enb.ul_earfcn); - sib13.add_field(new mbsfn_area_info_list_parser(&data->mbsfn_area_info_list_r9, nullptr)); + if (cellroot["ho_active"]) { + HANDLEPARSERCODE(parse_meas_cell_list(&rrc_cfg->meas_cfg, cellroot["meas_cell_list"])); + HANDLEPARSERCODE(parse_meas_report_desc(&rrc_cfg->meas_cfg, cellroot["meas_report_desc"])); + } - return parser::parse_section(std::move(filename), &sib13); -} -int mbsfn_area_info_list_parser::parse(Setting& root) -{ - if (not root.exists("mbsfn_area_info_list")) { - if (enabled) { - *enabled = false; + cell_cfg.scell_list.resize(cellroot["scell_list"].getLength()); + for (uint32_t i = 0; i < cell_cfg.scell_list.size(); ++i) { + auto& scell = cell_cfg.scell_list[i]; + auto& scellroot = cellroot["scell_list"][i]; + cell_id_parser(scell.cell_id, scellroot["cell_id"]); + scell.cross_carrier_sched = (bool)scellroot["cross_carrier_scheduling"]; + cell_id_parser(scell.sched_cell_id, scellroot["scheduling_cell_id"]); + scell.ul_allowed = (bool)scellroot["ul_allowed"]; } - mbsfn_list->resize(0); - return 0; } - mbsfn_list->resize(1); - if (enabled) { - *enabled = true; - } - mbsfn_area_info_r9_s* mbsfn_item = &(*mbsfn_list)[0]; + // Configuration check + for (auto it = rrc_cfg->cell_list.begin(); it != rrc_cfg->cell_list.end(); it++) { + for (auto it2 = it + 1; it2 != rrc_cfg->cell_list.end(); it2++) { + // Check RF port is not repeated + if (it->rf_port == it2->rf_port) { + ERROR("Repeated RF port for multiple cells\n"); + } - field_asn1_enum_str fieldlen("non_mbsfn_region_length", - &mbsfn_item->non_mbsfn_region_len); - if (fieldlen.parse(root["mbsfn_area_info_list"])) { - fprintf(stderr, "Error parsing non_mbsfn_region_length\n"); - return -1; + // Check cell ID is not repeated + if (it->cell_id == it2->cell_id) { + ERROR("Repeated Cell identifier\n"); + } + } } - field_asn1_enum_str repeat( - "mcch_repetition_period", &mbsfn_item->mcch_cfg_r9.mcch_repeat_period_r9); - if (repeat.parse(root["mbsfn_area_info_list"])) { - fprintf(stderr, "Error parsing mcch_repetition_period\n"); - return -1; - } + return SRSLTE_SUCCESS; +} - field_asn1_enum_str mod( - "mcch_modification_period", &mbsfn_item->mcch_cfg_r9.mcch_mod_period_r9); - if (mod.parse(root["mbsfn_area_info_list"])) { - fprintf(stderr, "Error parsing mcch_modification_period\n"); - return -1; - } +int cell_list_section::parse(libconfig::Setting& root) +{ + HANDLEPARSERCODE(parse_cell_list(args, rrc_cfg, root)); + return 0; +} - field_asn1_enum_str sig("signalling_mcs", - &mbsfn_item->mcch_cfg_r9.sig_mcs_r9); - if (sig.parse(root["mbsfn_area_info_list"])) { - fprintf(stderr, "Error parsing signalling_mcs\n"); - return -1; - } +} // namespace rr_sections - parser::field areaid("mbsfn_area_id", &mbsfn_item->mbsfn_area_id_r9); - if (areaid.parse(root["mbsfn_area_info_list"])) { - fprintf(stderr, "Error parsing mbsfn_area_id\n"); - return -1; - } +namespace enb_conf_sections { - parser::field notif_ind("notification_indicator", &mbsfn_item->notif_ind_r9); - if (notif_ind.parse(root["mbsfn_area_info_list"])) { - fprintf(stderr, "Error parsing notification_indicator\n"); - return -1; - } +int parse_cell_cfg(all_args_t* args_, srslte_cell_t* cell) +{ + cell->frame_type = SRSLTE_FDD; + cell->id = args_->enb.pci; + cell->cp = SRSLTE_CP_NORM; + cell->nof_ports = args_->enb.nof_ports; + cell->nof_prb = args_->enb.n_prb; - parser::field offset("mcch_offset", &mbsfn_item->mcch_cfg_r9.mcch_offset_r9); - if (offset.parse(root["mbsfn_area_info_list"])) { - fprintf(stderr, "Error parsing mcch_offset\n"); - return -1; - } + phich_cfg_s phichcfg; - field_asn1_bitstring_number, uint8_t> alloc_info("sf_alloc_info", - &mbsfn_item->mcch_cfg_r9.sf_alloc_info_r9); - if (alloc_info.parse(root["mbsfn_area_info_list"])) { - fprintf(stderr, "Error parsing mbsfn_area_info_list\n"); + parser::section phy_cnfg("phy_cnfg"); + parser::section phich_cnfg("phich_cnfg"); + phy_cnfg.add_subsection(&phich_cnfg); + phich_cnfg.add_field(make_asn1_enum_str_parser("duration", &phichcfg.phich_dur)); + phich_cnfg.add_field(make_asn1_enum_number_str_parser("resources", &phichcfg.phich_res)); + parser::parse_section(args_->enb_files.rr_config, &phy_cnfg); + + cell->phich_length = (srslte_phich_length_t)(int)phichcfg.phich_dur; + cell->phich_resources = (srslte_phich_r_t)(int)phichcfg.phich_res; + + if (!srslte_cell_isvalid(cell)) { + fprintf(stderr, "Invalid cell parameters: nof_prb=%d, cell_id=%d\n", args_->enb.n_prb, args_->stack.s1ap.cell_id); return -1; } return 0; } -int enb::parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_config_common) +int parse_cfg_files(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_) { - // FIXME: Leave 0 blank for now - 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_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(); + // Parse config files + srslte_cell_t cell_cfg = {}; - sib_type1_s* sib1 = &rrc_cfg_->sib1; - if (parse_sib1(args_->enb_files.sib_config, sib1)) { - return -1; - } - - // Fill rest of data from enb config - sib_type1_s::cell_access_related_info_s_* cell_access = &sib1->cell_access_related_info; - cell_access->cell_id.from_number((args_->stack.s1ap.enb_id << 8u) + args_->stack.s1ap.cell_id); - cell_access->tac.from_number(args_->stack.s1ap.tac); - sib1->freq_band_ind = (uint8_t)srslte_band_get_band(args_->enb.dl_earfcn); - std::string mnc_str; - if (not srslte::mnc_to_string(args_->stack.s1ap.mnc, &mnc_str)) { - ERROR("The provided mnc=%d is not valid", args_->stack.s1ap.mnc); - return -1; + if (enb_conf_sections::parse_cell_cfg(args_, &cell_cfg) != SRSLTE_SUCCESS) { + fprintf(stderr, "Error parsing Cell configuration\n"); + return SRSLTE_ERROR; } - std::string mcc_str; - if (not srslte::mcc_to_string(args_->stack.s1ap.mcc, &mcc_str)) { - ERROR("The provided mnc=%d is not valid", args_->stack.s1ap.mcc); - return -1; + if (sib_sections::parse_sibs(args_, rrc_cfg_, phy_cfg_) != SRSLTE_SUCCESS) { + fprintf(stderr, "Error parsing SIB configuration\n"); + return SRSLTE_ERROR; } - cell_access->plmn_id_list.resize(1); - srslte::plmn_id_t plmn; - if (plmn.from_string(mcc_str + mnc_str) == SRSLTE_ERROR) { - ERROR("Could not convert %s to a plmn_id\n", (mcc_str + mnc_str).c_str()); - return -1; + if (rr_sections::parse_rr(args_, rrc_cfg_) != SRSLTE_SUCCESS) { + fprintf(stderr, "Error parsing Radio Resources configuration\n"); + return SRSLTE_ERROR; } - srslte::to_asn1(&cell_access->plmn_id_list[0].plmn_id, plmn); - cell_access->plmn_id_list[0].cell_reserved_for_oper = plmn_id_info_s::cell_reserved_for_oper_e_::not_reserved; - sib1->cell_sel_info.q_rx_lev_min_offset = 0; - - // Generate SIB2 - if (parse_sib2(args_->enb_files.sib_config, sib2)) { - return -1; + if (drb_sections::parse_drb(args_, rrc_cfg_) != SRSLTE_SUCCESS) { + fprintf(stderr, "Error parsing DRB configuration\n"); + return SRSLTE_ERROR; } - // SRS not yet supported - sib2->rr_cfg_common.srs_ul_cfg_common.set(srs_ul_cfg_common_c::types::release); - if (sib2->freq_info.ul_bw_present) { - asn1::number_to_enum(sib2->freq_info.ul_bw, args_->enb.n_prb); - } - if (sib2->freq_info.ul_carrier_freq_present) { - sib2->freq_info.ul_carrier_freq = (uint16_t)args_->enb.ul_earfcn; - } + // Set fields derived from others, and check for correctness of the parsed configuration + return enb_conf_sections::set_derived_args(args_, rrc_cfg_, phy_cfg_, &cell_cfg); +} - // Update MBSFN list counter. Only 1 supported - if (not args_->stack.embms.enable) { - sib2->mbsfn_sf_cfg_list_present = false; - sib2->mbsfn_sf_cfg_list.resize(0); +int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_, srslte_cell_t* cell_cfg_) +{ + if (args_->enb.transmission_mode == 1) { + phy_cfg_->pdsch_cnfg.p_b = 0; // Default TM1 + rrc_cfg_->sibs[1].sib2().rr_cfg_common.pdsch_cfg_common.p_b = 0; } else { - // verify SIB13 is available - if (not sib_is_present(sib1->sched_info_list, sib_type_e::sib_type13_v920)) { - fprintf(stderr, "SIB13 not present in sched_info.\n"); - return -1; - } + phy_cfg_->pdsch_cnfg.p_b = 1; // Default TM2,3,4 + rrc_cfg_->sibs[1].sib2().rr_cfg_common.pdsch_cfg_common.p_b = 1; } - // Generate SIB3 if defined in mapping info - if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type3)) { - if (parse_sib3(args_->enb_files.sib_config, sib3)) { - return -1; - } - } + rrc_cfg_->inactivity_timeout_ms = args_->general.rrc_inactivity_timer; + rrc_cfg_->enable_mbsfn = args_->stack.embms.enable; - // Generate SIB4 if defined in mapping info - if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type4)) { - if (parse_sib4(args_->enb_files.sib_config, sib4)) { - return -1; - } - } + rrc_cfg_->dl_earfcn = args_->enb.dl_earfcn; + rrc_cfg_->pci = args_->enb.pci; - // Generate SIB7 if defined in mapping info - if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type7)) { - if (parse_sib7(args_->enb_files.sib_config, sib7)) { - return -1; - } + // Check number of control symbols + if (cell_cfg_->nof_prb < 50 && args_->stack.mac.sched.nof_ctrl_symbols != 3) { + args_->stack.mac.sched.nof_ctrl_symbols = 3; + fprintf(stdout, + "Setting number of control symbols to %d for %d PRB cell.\n", + args_->stack.mac.sched.nof_ctrl_symbols, + cell_cfg_->nof_prb); } - // Generate SIB9 if defined in mapping info - if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type9)) { - if (parse_sib9(args_->enb_files.sib_config, sib9)) { - return -1; + // Parse EEA preference list + std::vector eea_pref_list; + boost::split(eea_pref_list, args_->general.eea_pref_list, boost::is_any_of(",")); + int i = 0; + for (auto it = eea_pref_list.begin(); it != eea_pref_list.end() && i < srslte::CIPHERING_ALGORITHM_ID_N_ITEMS; it++) { + boost::trim_left(*it); + if ((*it) == "EEA0") { + rrc_cfg_->eea_preference_list[i] = srslte::CIPHERING_ALGORITHM_ID_EEA0; + i++; + } else if ((*it) == "EEA1") { + rrc_cfg_->eea_preference_list[i] = srslte::CIPHERING_ALGORITHM_ID_128_EEA1; + i++; + } else if ((*it) == "EEA2") { + rrc_cfg_->eea_preference_list[i] = srslte::CIPHERING_ALGORITHM_ID_128_EEA2; + i++; + } else if ((*it) == "EEA3") { + rrc_cfg_->eea_preference_list[i] = srslte::CIPHERING_ALGORITHM_ID_128_EEA3; + i++; + } else { + fprintf(stderr, "Failed to parse EEA prefence list %s \n", args_->general.eea_pref_list.c_str()); + return SRSLTE_ERROR; } } - if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type13_v920)) { - if (parse_sib13(args_->enb_files.sib_config, sib13)) { - return -1; + // Parse EIA preference list + std::vector eia_pref_list; + boost::split(eia_pref_list, args_->general.eia_pref_list, boost::is_any_of(",")); + i = 0; + for (auto it = eia_pref_list.begin(); it != eia_pref_list.end() && i < srslte::INTEGRITY_ALGORITHM_ID_N_ITEMS; it++) { + boost::trim_left(*it); + if ((*it) == "EIA0") { + rrc_cfg_->eia_preference_list[i] = srslte::INTEGRITY_ALGORITHM_ID_EIA0; + i++; + } else if ((*it) == "EIA1") { + rrc_cfg_->eia_preference_list[i] = srslte::INTEGRITY_ALGORITHM_ID_128_EIA1; + i++; + } else if ((*it) == "EIA2") { + rrc_cfg_->eia_preference_list[i] = srslte::INTEGRITY_ALGORITHM_ID_128_EIA2; + i++; + } else if ((*it) == "EIA3") { + rrc_cfg_->eia_preference_list[i] = srslte::INTEGRITY_ALGORITHM_ID_128_EIA3; + i++; + } else { + fprintf(stderr, "Failed to parse EIA prefence list %s \n", args_->general.eia_pref_list.c_str()); + return SRSLTE_ERROR; } } - // Copy PHY common configuration - bzero(&phy_config_common->cell, sizeof(phy_config_common->cell)); - phy_config_common->prach_cnfg = sib2->rr_cfg_common.prach_cfg; - phy_config_common->pdsch_cnfg = sib2->rr_cfg_common.pdsch_cfg_common; - phy_config_common->pusch_cnfg = sib2->rr_cfg_common.pusch_cfg_common; - phy_config_common->pucch_cnfg = sib2->rr_cfg_common.pucch_cfg_common; - phy_config_common->srs_ul_cnfg = sib2->rr_cfg_common.srs_ul_cfg_common; + // Copy cell struct to rrc and phy + rrc_cfg_->cell = *cell_cfg_; + phy_cfg_->cell = *cell_cfg_; - return 0; + // Patch certain args that are not exposed yet + args_->rf.nof_radios = 1; + args_->rf.nof_rf_channels = args_->phy.nof_carriers; + args_->rf.nof_rx_ant = args_->enb.nof_ports; + + return SRSLTE_SUCCESS; } -bool enb::sib_is_present(const sched_info_list_l& l, sib_type_e sib_num) +} // namespace enb_conf_sections + +namespace sib_sections { + +int parse_sib1(std::string filename, sib_type1_s* data) { - for (uint32_t i = 0; i < l.size(); i++) { - for (uint32_t j = 0; j < l[i].sib_map_info.size(); j++) { - if (l[i].sib_map_info[j] == sib_num) { - return true; - } - } - } - return false; + parser::section sib1("sib1"); + + sib1.add_field(make_asn1_enum_str_parser("intra_freq_reselection", &data->cell_access_related_info.intra_freq_resel)); + sib1.add_field(new parser::field("q_rx_lev_min", &data->cell_sel_info.q_rx_lev_min)); + sib1.add_field(new parser::field("p_max", &data->p_max, &data->p_max_present)); + sib1.add_field(make_asn1_enum_str_parser("cell_barred", &data->cell_access_related_info.cell_barred)); + sib1.add_field(make_asn1_enum_number_parser("si_window_length", &data->si_win_len)); + sib1.add_field(new parser::field("system_info_value_tag", &data->sys_info_value_tag)); + + // sched_info subsection uses a custom field class + parser::section sched_info("sched_info"); + sib1.add_subsection(&sched_info); + sched_info.add_field(new field_sched_info(data)); + + // Run parser with single section + return parser::parse_section(std::move(filename), &sib1); } -int enb::parse_rr(all_args_t* args_, rrc_cfg_t* rrc_cfg_) +int parse_sib2(std::string filename, sib_type2_s* data) { - /* Transmission mode config section */ - if (args_->enb.transmission_mode < 1 || args_->enb.transmission_mode > 4) { - ERROR("Invalid transmission mode (%d). Only indexes 1-4 are implemented.\n", args_->enb.transmission_mode); - return SRSLTE_ERROR; - } else if (args_->enb.transmission_mode == 1 && args_->enb.nof_ports > 1) { - ERROR("Invalid number of ports (%d) for transmission mode (%d). Only one antenna port is allowed.\n", - args_->enb.nof_ports, - args_->enb.transmission_mode); - return SRSLTE_ERROR; - } else if (args_->enb.transmission_mode > 1 && args_->enb.nof_ports != 2) { - ERROR("The selected number of ports (%d) are insufficient for the selected transmission mode (%d).\n", - args_->enb.nof_ports, - args_->enb.transmission_mode); - return SRSLTE_ERROR; - } + parser::section sib2("sib2"); - rrc_cfg_->antenna_info.tx_mode = (ant_info_ded_s::tx_mode_e_::options)(args_->enb.transmission_mode - 1); + sib2.add_field(make_asn1_enum_str_parser("time_alignment_timer", &data->time_align_timer_common)); + sib2.add_field(new mbsfn_sf_cfg_list_parser(&data->mbsfn_sf_cfg_list, &data->mbsfn_sf_cfg_list_present)); - rrc_cfg_->antenna_info.ue_tx_ant_sel.set_setup(); - switch (rrc_cfg_->antenna_info.tx_mode) { - case ant_info_ded_s::tx_mode_e_::tm1: - case ant_info_ded_s::tx_mode_e_::tm2: - rrc_cfg_->antenna_info.ue_tx_ant_sel.set(setup_e::release); - rrc_cfg_->antenna_info.codebook_subset_restrict_present = false; - break; - case ant_info_ded_s::tx_mode_e_::tm3: - rrc_cfg_->antenna_info.ue_tx_ant_sel.setup().value = ant_info_ded_s::ue_tx_ant_sel_c_::setup_e_::open_loop; + parser::section freqinfo("freqInfo"); + sib2.add_subsection(&freqinfo); + freqinfo.add_field(new parser::field("additional_spectrum_emission", &data->freq_info.add_spec_emission)); + freqinfo.add_field(new parser::field("ul_carrier_freq_present", &data->freq_info.ul_carrier_freq_present)); + freqinfo.add_field(new parser::field("ul_bw_present", &data->freq_info.ul_bw_present)); - rrc_cfg_->antenna_info.codebook_subset_restrict_present = true; - rrc_cfg_->antenna_info.codebook_subset_restrict.set_n2_tx_ant_tm3(); - rrc_cfg_->antenna_info.codebook_subset_restrict.n2_tx_ant_tm3().from_number(0b11); - break; - case ant_info_ded_s::tx_mode_e_::tm4: - rrc_cfg_->antenna_info.ue_tx_ant_sel.setup().value = ant_info_ded_s::ue_tx_ant_sel_c_::setup_e_::closed_loop; + // AC barring configuration + parser::section acbarring("ac_barring"); + sib2.add_subsection(&acbarring); + acbarring.set_optional(&data->ac_barr_info_present); - rrc_cfg_->antenna_info.codebook_subset_restrict_present = true; - rrc_cfg_->antenna_info.codebook_subset_restrict.set_n2_tx_ant_tm4(); - rrc_cfg_->antenna_info.codebook_subset_restrict.n2_tx_ant_tm4().from_number(0b111111); - break; - default: - ERROR("Unsupported transmission mode %d\n", rrc_cfg_->antenna_info.tx_mode.to_number()); - return SRSLTE_ERROR; - } + acbarring.add_field(new parser::field("ac_barring_for_emergency", &data->ac_barr_info.ac_barr_for_emergency)); - /* Parse power allocation */ - if (not asn1::number_to_enum(rrc_cfg_->pdsch_cfg, args_->enb.p_a)) { - ERROR("Invalid p_a value (%f) only -6, -4.77, -3, -1.77, 0, 1, 2, 3 values allowed.", args_->enb.p_a); - return SRSLTE_ERROR; - } + parser::section acbarring_signalling("ac_barring_for_mo_signalling"); + acbarring.add_subsection(&acbarring_signalling); + acbarring_signalling.set_optional(&data->ac_barr_info.ac_barr_for_mo_sig_present); - /* MAC config section */ - parser::section mac_cnfg("mac_cnfg"); - parser::section phr_cnfg("phr_cnfg"); - mac_cnfg.add_subsection(&phr_cnfg); - rrc_cfg_->mac_cnfg.phr_cfg.set( - mac_main_cfg_s::phr_cfg_c_::types::release); // default is release if "phr_cnfg" is not found - mac_cnfg.add_field(new phr_cnfg_parser(&rrc_cfg_->mac_cnfg.phr_cfg)); - // mac_cnfg.add_field(new phr_cnfg_parser(&rrc_cfg_->mac_cnfg.phr_cfg)); + acbarring_signalling.add_field( + make_asn1_enum_number_str_parser("factor", &data->ac_barr_info.ac_barr_for_mo_sig.ac_barr_factor)); + acbarring_signalling.add_field( + make_asn1_enum_number_parser("time", &data->ac_barr_info.ac_barr_for_mo_sig.ac_barr_time)); + acbarring_signalling.add_field(make_asn1_bitstring_number_parser( + "for_special_ac", &data->ac_barr_info.ac_barr_for_mo_sig.ac_barr_for_special_ac)); - parser::section ulsch_cnfg("ulsch_cnfg"); - mac_cnfg.add_subsection(&ulsch_cnfg); + parser::section acbarring_data("ac_barring_for_mo_data"); + acbarring.add_subsection(&acbarring_data); + acbarring_data.set_optional(&data->ac_barr_info.ac_barr_for_mo_data_present); - rrc_cfg_->mac_cnfg.ul_sch_cfg.tti_bundling = false; - ulsch_cnfg.add_field(make_asn1_enum_number_parser( - "max_harq_tx", &rrc_cfg_->mac_cnfg.ul_sch_cfg.max_harq_tx, &rrc_cfg_->mac_cnfg.ul_sch_cfg.max_harq_tx_present)); - ulsch_cnfg.add_field(make_asn1_enum_number_parser("periodic_bsr_timer", - &rrc_cfg_->mac_cnfg.ul_sch_cfg.periodic_bsr_timer, - &rrc_cfg_->mac_cnfg.ul_sch_cfg.periodic_bsr_timer_present)); - ulsch_cnfg.add_field(make_asn1_enum_number_parser("retx_bsr_timer", &rrc_cfg_->mac_cnfg.ul_sch_cfg.retx_bsr_timer)); + acbarring_data.add_field( + make_asn1_enum_number_str_parser("factor", &data->ac_barr_info.ac_barr_for_mo_data.ac_barr_factor)); + acbarring_data.add_field(make_asn1_enum_number_parser("fime", &data->ac_barr_info.ac_barr_for_mo_data.ac_barr_time)); + acbarring_data.add_field(make_asn1_bitstring_number_parser( + "for_special_ac", &data->ac_barr_info.ac_barr_for_mo_data.ac_barr_for_special_ac)); - mac_cnfg.add_field(make_asn1_enum_number_parser("time_alignment_timer", &rrc_cfg_->mac_cnfg.time_align_timer_ded)); + // UE timers and constants + parser::section uetimers("ue_timers_and_constants"); + sib2.add_subsection(&uetimers); + uetimers.add_field(make_asn1_enum_number_parser("t300", &data->ue_timers_and_consts.t300)); + uetimers.add_field(make_asn1_enum_number_parser("t301", &data->ue_timers_and_consts.t301)); + uetimers.add_field(make_asn1_enum_number_parser("t310", &data->ue_timers_and_consts.t310)); + uetimers.add_field(make_asn1_enum_number_parser("n310", &data->ue_timers_and_consts.n310)); + uetimers.add_field(make_asn1_enum_number_parser("t311", &data->ue_timers_and_consts.t311)); + uetimers.add_field(make_asn1_enum_number_parser("n311", &data->ue_timers_and_consts.n311)); - /* PHY config section */ - parser::section phy_cfg_("phy_cnfg"); + // Radio-resource configuration section + parser::section rr_config("rr_config_common_sib"); + sib2.add_subsection(&rr_config); + rr_cfg_common_sib_s* rr_cfg_common = &data->rr_cfg_common; - parser::section pusch_cnfg_ded("pusch_cnfg_ded"); - phy_cfg_.add_subsection(&pusch_cnfg_ded); + rr_config.add_field(make_asn1_enum_str_parser("ul_cp_length", &rr_cfg_common->ul_cp_len)); - pusch_cnfg_ded.add_field(new parser::field("beta_offset_ack_idx", &rrc_cfg_->pusch_cfg.beta_offset_ack_idx)); - pusch_cnfg_ded.add_field(new parser::field("beta_offset_ri_idx", &rrc_cfg_->pusch_cfg.beta_offset_ri_idx)); - pusch_cnfg_ded.add_field(new parser::field("beta_offset_cqi_idx", &rrc_cfg_->pusch_cfg.beta_offset_cqi_idx)); + // RACH configuration + parser::section rach_cnfg("rach_cnfg"); + rr_config.add_subsection(&rach_cnfg); - parser::section sched_request_cnfg("sched_request_cnfg"); - phy_cfg_.add_subsection(&sched_request_cnfg); + rach_cnfg.add_field( + make_asn1_enum_number_parser("num_ra_preambles", &rr_cfg_common->rach_cfg_common.preamb_info.nof_ra_preambs)); + rach_cnfg.add_field(make_asn1_enum_number_parser( + "preamble_init_rx_target_pwr", &rr_cfg_common->rach_cfg_common.pwr_ramp_params.preamb_init_rx_target_pwr)); + rach_cnfg.add_field( + make_asn1_enum_number_parser("pwr_ramping_step", &rr_cfg_common->rach_cfg_common.pwr_ramp_params.pwr_ramp_step)); + rach_cnfg.add_field(make_asn1_enum_number_parser( + "preamble_trans_max", &rr_cfg_common->rach_cfg_common.ra_supervision_info.preamb_trans_max)); + rach_cnfg.add_field(make_asn1_enum_number_parser( + "ra_resp_win_size", &rr_cfg_common->rach_cfg_common.ra_supervision_info.ra_resp_win_size)); + rach_cnfg.add_field(make_asn1_enum_number_parser( + "mac_con_res_timer", &rr_cfg_common->rach_cfg_common.ra_supervision_info.mac_contention_resolution_timer)); + rach_cnfg.add_field(new parser::field("max_harq_msg3_tx", &rr_cfg_common->rach_cfg_common.max_harq_msg3_tx)); - sched_request_cnfg.add_field(make_asn1_enum_number_parser("dsr_trans_max", &rrc_cfg_->sr_cfg.dsr_max)); - sched_request_cnfg.add_field(new parser::field("period", &rrc_cfg_->sr_cfg.period)); - sched_request_cnfg.add_field(new parser::field("nof_prb", &rrc_cfg_->sr_cfg.nof_prb)); - sched_request_cnfg.add_field(new field_sf_mapping(rrc_cfg_->sr_cfg.sf_mapping, &rrc_cfg_->sr_cfg.nof_subframes)); + parser::section groupa_cnfg("preambles_group_a_cnfg"); + rach_cnfg.add_subsection(&groupa_cnfg); + groupa_cnfg.set_optional(&rr_cfg_common->rach_cfg_common.preamb_info.preambs_group_a_cfg_present); + rach_cfg_common_s::preamb_info_s_::preambs_group_a_cfg_s_* group_acfg = + &rr_cfg_common->rach_cfg_common.preamb_info.preambs_group_a_cfg; + groupa_cnfg.add_field(make_asn1_enum_number_parser("size_of_ra", &group_acfg->size_of_ra_preambs_group_a)); + groupa_cnfg.add_field(make_asn1_enum_number_parser("msg_size", &group_acfg->msg_size_group_a)); + groupa_cnfg.add_field(make_asn1_enum_number_parser("msg_pwr_offset_group_b", &group_acfg->msg_pwr_offset_group_b)); + // rr_cfg_common->rach_cfg_common.preamb_info.nof_ra_preambs = FIXME: ??? + + // BCCH configuration + parser::section bcch_cnfg("bcch_cnfg"); + rr_config.add_subsection(&bcch_cnfg); + bcch_cnfg.add_field( + make_asn1_enum_number_parser("modification_period_coeff", &rr_cfg_common->bcch_cfg.mod_period_coeff)); + + // PCCH configuration + parser::section pcch_cnfg("pcch_cnfg"); + rr_config.add_subsection(&pcch_cnfg); + pcch_cnfg.add_field( + make_asn1_enum_number_parser("default_paging_cycle", &rr_cfg_common->pcch_cfg.default_paging_cycle)); + pcch_cnfg.add_field(make_asn1_enum_number_str_parser("nB", &rr_cfg_common->pcch_cfg.nb)); + + // PRACH configuration + parser::section prach_cnfg("prach_cnfg"); + rr_config.add_subsection(&prach_cnfg); + prach_cnfg.add_field(new parser::field("root_sequence_index", &rr_cfg_common->prach_cfg.root_seq_idx)); + parser::section prach_cnfg_info("prach_cnfg_info"); + prach_cnfg.add_subsection(&prach_cnfg_info); + prach_cnfg_info.add_field( + new parser::field("high_speed_flag", &rr_cfg_common->prach_cfg.prach_cfg_info.high_speed_flag)); + prach_cnfg_info.add_field( + new parser::field("prach_config_index", &rr_cfg_common->prach_cfg.prach_cfg_info.prach_cfg_idx)); + prach_cnfg_info.add_field( + new parser::field("prach_freq_offset", &rr_cfg_common->prach_cfg.prach_cfg_info.prach_freq_offset)); + prach_cnfg_info.add_field(new parser::field( + "zero_correlation_zone_config", &rr_cfg_common->prach_cfg.prach_cfg_info.zero_correlation_zone_cfg)); + + // PDSCH configuration + parser::section pdsch_cnfg("pdsch_cnfg"); + rr_config.add_subsection(&pdsch_cnfg); + pdsch_cnfg.add_field(new parser::field("p_b", &rr_cfg_common->pdsch_cfg_common.p_b)); + pdsch_cnfg.add_field(new parser::field("rs_power", &rr_cfg_common->pdsch_cfg_common.ref_sig_pwr)); + + // PUSCH configuration + parser::section pusch_cnfg("pusch_cnfg"); + rr_config.add_subsection(&pusch_cnfg); + pusch_cnfg.add_field(new parser::field("n_sb", &rr_cfg_common->pusch_cfg_common.pusch_cfg_basic.n_sb)); + pusch_cnfg.add_field( + make_asn1_enum_str_parser("hopping_mode", &rr_cfg_common->pusch_cfg_common.pusch_cfg_basic.hop_mode)); + pusch_cnfg.add_field(new parser::field("pusch_hopping_offset", + &rr_cfg_common->pusch_cfg_common.pusch_cfg_basic.pusch_hop_offset)); + pusch_cnfg.add_field( + new parser::field("enable_64_qam", &rr_cfg_common->pusch_cfg_common.pusch_cfg_basic.enable64_qam)); - parser::section cqi_report_cnfg("cqi_report_cnfg"); - phy_cfg_.add_subsection(&cqi_report_cnfg); + // PUSCH-ULRS configuration + parser::section ulrs_cnfg("ul_rs"); + pusch_cnfg.add_subsection(&ulrs_cnfg); + ulrs_cnfg.add_field( + new parser::field("cyclic_shift", &rr_cfg_common->pusch_cfg_common.ul_ref_sigs_pusch.cyclic_shift)); + ulrs_cnfg.add_field(new parser::field("group_assignment_pusch", + &rr_cfg_common->pusch_cfg_common.ul_ref_sigs_pusch.group_assign_pusch)); + ulrs_cnfg.add_field(new parser::field("group_hopping_enabled", + &rr_cfg_common->pusch_cfg_common.ul_ref_sigs_pusch.group_hop_enabled)); + ulrs_cnfg.add_field(new parser::field("sequence_hopping_enabled", + &rr_cfg_common->pusch_cfg_common.ul_ref_sigs_pusch.seq_hop_enabled)); - cqi_report_cnfg.add_field(new parser::field_enum_str( - "mode", &rrc_cfg_->cqi_cfg.mode, rrc_cfg_cqi_mode_text, RRC_CFG_CQI_MODE_N_ITEMS)); - cqi_report_cnfg.add_field(new parser::field("period", &rrc_cfg_->cqi_cfg.period)); - cqi_report_cnfg.add_field(new parser::field("m_ri", &rrc_cfg_->cqi_cfg.m_ri)); - cqi_report_cnfg.add_field(new parser::field("nof_prb", &rrc_cfg_->cqi_cfg.nof_prb)); - cqi_report_cnfg.add_field(new parser::field("simultaneousAckCQI", &rrc_cfg_->cqi_cfg.simultaneousAckCQI)); - cqi_report_cnfg.add_field(new field_sf_mapping(rrc_cfg_->cqi_cfg.sf_mapping, &rrc_cfg_->cqi_cfg.nof_subframes)); + // PUCCH configuration + parser::section pucch_cnfg("pucch_cnfg"); + rr_config.add_subsection(&pucch_cnfg); + pucch_cnfg.add_field( + make_asn1_enum_number_parser("delta_pucch_shift", &rr_cfg_common->pucch_cfg_common.delta_pucch_shift)); + pucch_cnfg.add_field(new parser::field("n_rb_cqi", &rr_cfg_common->pucch_cfg_common.n_rb_cqi)); + pucch_cnfg.add_field(new parser::field("n_cs_an", &rr_cfg_common->pucch_cfg_common.n_cs_an)); + pucch_cnfg.add_field(new parser::field("n1_pucch_an", &rr_cfg_common->pucch_cfg_common.n1_pucch_an)); - /* RRC config section */ - parser::section rrc_cnfg("cell_list"); - rrc_cnfg.set_optional(&rrc_cfg_->meas_cfg_present); - rrc_cnfg.add_field(new rr_sections::cell_list_section(args_, rrc_cfg_)); + // UL PWR Ctrl configuration + parser::section ul_pwr_ctrl("ul_pwr_ctrl"); + rr_config.add_subsection(&ul_pwr_ctrl); + ul_pwr_ctrl.add_field( + new parser::field("p0_nominal_pusch", &rr_cfg_common->ul_pwr_ctrl_common.p0_nominal_pusch)); + ul_pwr_ctrl.add_field(make_asn1_enum_number_parser("alpha", &rr_cfg_common->ul_pwr_ctrl_common.alpha)); + ul_pwr_ctrl.add_field( + new parser::field("p0_nominal_pucch", &rr_cfg_common->ul_pwr_ctrl_common.p0_nominal_pucch)); + ul_pwr_ctrl.add_field( + new parser::field("delta_preamble_msg3", &rr_cfg_common->ul_pwr_ctrl_common.delta_preamb_msg3)); - // Run parser with two sections - parser p(args_->enb_files.rr_config); - p.add_section(&mac_cnfg); - p.add_section(&phy_cfg_); - p.add_section(&rrc_cnfg); - return p.parse(); -} + // Delta Flist PUCCH + parser::section delta_flist("delta_flist_pucch"); + ul_pwr_ctrl.add_subsection(&delta_flist); + delta_flist.add_field(make_asn1_enum_number_parser( + "format_1", &rr_cfg_common->ul_pwr_ctrl_common.delta_flist_pucch.delta_f_pucch_format1)); + delta_flist.add_field(make_asn1_enum_number_parser( + "format_1b", &rr_cfg_common->ul_pwr_ctrl_common.delta_flist_pucch.delta_f_pucch_format1b)); + delta_flist.add_field(make_asn1_enum_number_parser( + "format_2", &rr_cfg_common->ul_pwr_ctrl_common.delta_flist_pucch.delta_f_pucch_format2)); + delta_flist.add_field(make_asn1_enum_number_parser( + "format_2a", &rr_cfg_common->ul_pwr_ctrl_common.delta_flist_pucch.delta_f_pucch_format2a)); + delta_flist.add_field(make_asn1_enum_number_parser( + "format_2b", &rr_cfg_common->ul_pwr_ctrl_common.delta_flist_pucch.delta_f_pucch_format2b)); -int field_sf_mapping::parse(libconfig::Setting& root) -{ - *nof_subframes = root["subframe"].getLength(); - for (uint32_t i = 0; i < *nof_subframes; i++) { - sf_mapping[i] = root["subframe"][i]; - } - return 0; + // Run parser with single section + return parser::parse_section(std::move(filename), &sib2); } -int phr_cnfg_parser::parse(libconfig::Setting& root) +int parse_sib3(std::string filename, sib_type3_s* data) { - if (not root.exists("phr_cnfg")) { - phr_cfg->set(mac_main_cfg_s::phr_cfg_c_::types::release); - return 0; - } - phr_cfg->set_setup(); - mac_main_cfg_s::phr_cfg_c_::setup_s_& s = phr_cfg->setup(); + parser::section sib3("sib3"); - if (not parse_enum_by_str(s.dl_pathloss_change, "dl_pathloss_change", root["phr_cnfg"])) { - return -1; - } - if (not parse_enum_by_number(s.periodic_phr_timer, "periodic_phr_timer", root["phr_cnfg"])) { - return -1; - } - if (not parse_enum_by_number(s.prohibit_phr_timer, "prohibit_phr_timer", root["phr_cnfg"])) { - return -1; - } - return 0; -} + // CellReselectionInfoCommon + parser::section resel_common("cell_reselection_common"); + sib3.add_subsection(&resel_common); -int enb::parse_drb(all_args_t* args_, rrc_cfg_t* rrc_cfg_) -{ - parser::section qci("qci_config"); - qci.add_field(new field_qci(rrc_cfg_->qci_cfg)); - return parser::parse_section(args_->enb_files.drb_config, &qci); -} + resel_common.add_field(make_asn1_enum_number_parser("q_hyst", &data->cell_resel_info_common.q_hyst)); -int field_qci::parse(libconfig::Setting& root) -{ - auto nof_qci = (uint32_t)root.getLength(); + parser::section speed_resel("speed_state_resel_params"); + resel_common.add_subsection(&speed_resel); + resel_common.set_optional(&data->cell_resel_info_common.speed_state_resel_pars_present); + sib_type3_s::cell_resel_info_common_s_::speed_state_resel_pars_s_* resel_pars = + &data->cell_resel_info_common.speed_state_resel_pars; - for (uint32_t i = 0; i < MAX_NOF_QCI; i++) { - cfg->configured = false; - } + parser::section q_hyst_sf("q_hyst_sf"); + speed_resel.add_subsection(&q_hyst_sf); + q_hyst_sf.add_field(make_asn1_enum_number_parser("medium", &resel_pars->q_hyst_sf.sf_medium)); + q_hyst_sf.add_field(make_asn1_enum_number_parser("high", &resel_pars->q_hyst_sf.sf_high)); - for (uint32_t i = 0; i < nof_qci; i++) { - libconfig::Setting& q = root[i]; + parser::section mob_params("mobility_state_params"); + speed_resel.add_subsection(&mob_params); + mob_params.add_field(make_asn1_enum_number_parser("t_eval", &resel_pars->mob_state_params.t_eval)); + mob_params.add_field(make_asn1_enum_number_parser("t_hyst_normal", &resel_pars->mob_state_params.t_hyst_normal)); + mob_params.add_field( + new parser::field("n_cell_change_medium", &resel_pars->mob_state_params.n_cell_change_medium)); + mob_params.add_field( + new parser::field("n_cell_change_high", &resel_pars->mob_state_params.n_cell_change_high)); - uint32_t qci = q["qci"]; + // CellReselectionServingFreqInfo + parser::section resel_serving("cell_reselection_serving"); + sib3.add_subsection(&resel_serving); + sib_type3_s::cell_resel_serving_freq_info_s_* freqinfo = &data->cell_resel_serving_freq_info; - // Parse PDCP section - if (!q.exists("pdcp_config")) { - fprintf(stderr, "Error section pdcp_config not found for qci=%d\n", qci); - return -1; - } + resel_serving.add_field(new parser::field( + "s_non_intra_search", &freqinfo->s_non_intra_search, &freqinfo->s_non_intra_search_present)); + resel_serving.add_field(new parser::field("thresh_serving_low", &freqinfo->thresh_serving_low)); + resel_serving.add_field(new parser::field("cell_resel_prio", &freqinfo->cell_resel_prio)); - field_asn1_enum_number discard_timer( - "discard_timer", &cfg[qci].pdcp_cfg.discard_timer, &cfg[qci].pdcp_cfg.discard_timer_present); - discard_timer.parse(q["pdcp_config"]); + // intraFreqCellReselectionInfo + parser::section intra_freq("intra_freq_reselection"); + sib3.add_subsection(&intra_freq); + sib_type3_s::intra_freq_cell_resel_info_s_* intrafreq = &data->intra_freq_cell_resel_info; - field_asn1_enum_number pdcp_sn_size( - "pdcp_sn_size", &cfg[qci].pdcp_cfg.rlc_um.pdcp_sn_size, &cfg[qci].pdcp_cfg.rlc_um_present); - pdcp_sn_size.parse(q["pdcp_config"]); + intra_freq.add_field(new parser::field("q_rx_lev_min", &intrafreq->q_rx_lev_min)); + intra_freq.add_field(new parser::field("p_max", &intrafreq->p_max, &intrafreq->p_max_present)); + intra_freq.add_field( + new parser::field("s_intra_search", &intrafreq->s_intra_search, &intrafreq->s_intra_search_present)); + intra_freq.add_field(make_asn1_enum_number_parser( + "allowed_meas_bw", &intrafreq->allowed_meas_bw, &intrafreq->allowed_meas_bw_present)); + intra_freq.add_field(new parser::field("presence_ant_port_1", &intrafreq->presence_ant_port1)); + intra_freq.add_field(make_asn1_bitstring_number_parser("neigh_cell_cnfg", &intrafreq->neigh_cell_cfg)); + intra_freq.add_field(new parser::field("t_resel_eutra", &intrafreq->t_resel_eutra)); - cfg[qci].pdcp_cfg.rlc_am_present = - q["pdcp_config"].lookupValue("status_report_required", cfg[qci].pdcp_cfg.rlc_am.status_report_required); - cfg[qci].pdcp_cfg.hdr_compress.set(pdcp_cfg_s::hdr_compress_c_::types::not_used); + parser::section t_resel_eutra_sf("t_resel_eutra_sf"); + intra_freq.add_subsection(&t_resel_eutra_sf); + t_resel_eutra_sf.set_optional(&intrafreq->t_resel_eutra_sf_present); - // Parse RLC section - rlc_cfg_c* rlc_cfg = &cfg[qci].rlc_cfg; - if (q["rlc_config"].exists("ul_am")) { - rlc_cfg->set_am(); - } else if (q["rlc_config"].exists("ul_um") && q["rlc_config"].exists("dl_um")) { - rlc_cfg->set_um_bi_dir(); - } else if (q["rlc_config"].exists("ul_um") && !q["rlc_config"].exists("dl_um")) { - rlc_cfg->set_um_uni_dir_ul(); - } else if (!q["rlc_config"].exists("ul_um") && q["rlc_config"].exists("dl_um")) { - rlc_cfg->set_um_uni_dir_dl(); - } else { - fprintf(stderr, "Invalid combination of UL/DL UM/AM for qci=%d\n", qci); - return -1; - } + t_resel_eutra_sf.add_field(make_asn1_enum_number_str_parser("sf_medium", &intrafreq->t_resel_eutra_sf.sf_medium)); + t_resel_eutra_sf.add_field(make_asn1_enum_number_str_parser("sf_high", &intrafreq->t_resel_eutra_sf.sf_high)); - // Parse RLC-UM section - if (q["rlc_config"].exists("ul_um")) { + // Run parser with single section + return parser::parse_section(std::move(filename), &sib3); +} - ul_um_rlc_s* um_rlc; - if (rlc_cfg->type() == rlc_cfg_c::types::um_uni_dir_ul) { - um_rlc = &rlc_cfg->um_uni_dir_ul().ul_um_rlc; - } else { - um_rlc = &rlc_cfg->um_bi_dir().ul_um_rlc; - } +int parse_sib4(std::string filename, sib_type4_s* data) +{ + parser::section sib4("sib4"); - field_asn1_enum_number sn_field_len("sn_field_length", &um_rlc->sn_field_len); - if (sn_field_len.parse(q["rlc_config"]["ul_um"])) { - ERROR("Error can't find sn_field_length in section ul_um\n"); - } - } + // csg-PhysCellIdRange + parser::section csg_range("csg_phys_cell_id_range"); + sib4.add_subsection(&csg_range); + csg_range.set_optional(&data->csg_pci_range_present); + csg_range.add_field(make_asn1_enum_number_parser("range", &data->csg_pci_range.range)); + csg_range.add_field(new parser::field("start", &data->csg_pci_range.start)); - if (q["rlc_config"].exists("dl_um")) { + // intraFreqNeighCellList + parser::section intra_neigh("intra_freq_neigh_cell_list"); + sib4.add_subsection(&intra_neigh); + bool dummy_bool = false; + intra_neigh.set_optional(&dummy_bool); + intra_neigh.add_field(new field_intra_neigh_cell_list(data)); - dl_um_rlc_s* um_rlc; - if (rlc_cfg->type() == rlc_cfg_c::types::um_uni_dir_dl) { - um_rlc = &rlc_cfg->um_uni_dir_dl().dl_um_rlc; - } else { - um_rlc = &rlc_cfg->um_bi_dir().dl_um_rlc; - } + // intraFreqBlackCellList + parser::section intra_black("intra_freq_black_cell_list"); + sib4.add_subsection(&intra_black); + intra_black.set_optional(&dummy_bool); + intra_black.add_field(new field_intra_black_cell_list(data)); - field_asn1_enum_number sn_field_len("sn_field_length", &um_rlc->sn_field_len); - if (sn_field_len.parse(q["rlc_config"]["dl_um"])) { - ERROR("Error can't find sn_field_length in section dl_um\n"); - } + // Run parser with single section + return parser::parse_section(std::move(filename), &sib4); +} - field_asn1_enum_number t_reordering("t_reordering", &um_rlc->t_reordering); - if (t_reordering.parse(q["rlc_config"]["dl_um"])) { - ERROR("Error can't find t_reordering in section dl_um\n"); - } - } +int parse_sib7(std::string filename, sib_type7_s* data) +{ + parser::section sib7("sib7"); - // Parse RLC-AM section - if (q["rlc_config"].exists("ul_am")) { - ul_am_rlc_s* am_rlc = &rlc_cfg->am().ul_am_rlc; + sib7.add_field(new parser::field("t_resel_geran", &data->t_resel_geran)); + // TODO: t_resel_geran_sf - field_asn1_enum_number t_poll_retx("t_poll_retx", &am_rlc->t_poll_retx); - if (t_poll_retx.parse(q["rlc_config"]["ul_am"])) { - ERROR("Error can't find t_poll_retx in section ul_am\n"); - } + data->carrier_freqs_info_list_present = true; + parser::section geran_neigh("carrier_freqs_info_list"); + sib7.add_subsection(&geran_neigh); - field_asn1_enum_number poll_pdu("poll_pdu", &am_rlc->poll_pdu); - if (poll_pdu.parse(q["rlc_config"]["ul_am"])) { - ERROR("Error can't find poll_pdu in section ul_am\n"); - } + bool dummy_bool = false; + geran_neigh.set_optional(&dummy_bool); + geran_neigh.add_field(new field_carrier_freqs_info_list(data)); - field_asn1_enum_number poll_byte("poll_byte", &am_rlc->poll_byte); - if (poll_byte.parse(q["rlc_config"]["ul_am"])) { - ERROR("Error can't find poll_byte in section ul_am\n"); - } + return parser::parse_section(std::move(filename), &sib7); +} - field_asn1_enum_number max_retx_thresh("max_retx_thresh", - &am_rlc->max_retx_thres); - if (max_retx_thresh.parse(q["rlc_config"]["ul_am"])) { - ERROR("Error can't find max_retx_thresh in section ul_am\n"); - } - } +int parse_sib9(std::string filename, sib_type9_s* data) +{ + parser::section sib9("sib9"); - if (q["rlc_config"].exists("dl_am")) { - dl_am_rlc_s* am_rlc = &rlc_cfg->am().dl_am_rlc; + bool name_enabled, hex_enabled; + std::string hnb_name, hex_value; - field_asn1_enum_number t_reordering("t_reordering", &am_rlc->t_reordering); - if (t_reordering.parse(q["rlc_config"]["dl_am"])) { - ERROR("Error can't find t_reordering in section dl_am\n"); - } + sib9.add_field(new parser::field("hnb_name", &hnb_name, &name_enabled)); + sib9.add_field(new parser::field("hex_value", &hex_value, &hex_enabled)); - field_asn1_enum_number t_status_prohibit("t_status_prohibit", &am_rlc->t_status_prohibit); - if (t_status_prohibit.parse(q["rlc_config"]["dl_am"])) { - ERROR("Error can't find t_status_prohibit in section dl_am\n"); + // Run parser with single section + if (!parser::parse_section(std::move(filename), &sib9)) { + data->hnb_name_present = true; + if (name_enabled) { + data->hnb_name.resize(SRSLTE_MIN((uint32_t)hnb_name.size(), 48)); + memcpy(data->hnb_name.data(), hnb_name.c_str(), data->hnb_name.size()); + } else if (hex_enabled) { + if (hex_value.size() > 48) { + hex_value.resize(48); } + data->hnb_name.from_string(hex_value); + } else { + data->hnb_name_present = false; } + return 0; + } else { + return -1; + } +} - // Parse logical channel configuration section - if (!q.exists("logical_channel_config")) { - fprintf(stderr, "Error section logical_channel_config not found for qci=%d\n", qci); - return -1; - } +int parse_sib13(std::string filename, sib_type13_r9_s* data) +{ + parser::section sib13("sib13"); - lc_ch_cfg_s::ul_specific_params_s_* lc_cfg = &cfg[qci].lc_cfg; + sib13.add_field(make_asn1_seqof_size_parser("mbsfn_area_info_list_size", &data->mbsfn_area_info_list_r9)); - parser::field priority("priority", &lc_cfg->prio); - if (priority.parse(q["logical_channel_config"])) { - ERROR("Error can't find logical_channel_config in section priority\n"); - } + parser::section mbsfn_notification_config("mbsfn_notification_config"); + sib13.add_subsection(&mbsfn_notification_config); - field_asn1_enum_number prioritised_bit_rate( - "prioritized_bit_rate", &lc_cfg->prioritised_bit_rate); - if (prioritised_bit_rate.parse(q["logical_channel_config"])) { - fprintf(stderr, "Error can't find prioritized_bit_rate in section logical_channel_config\n"); - } + mbsfn_notification_config.add_field( + make_asn1_enum_str_parser("mbsfn_notification_repetition_coeff", &data->notif_cfg_r9.notif_repeat_coeff_r9)); - field_asn1_enum_number bucket_size_duration( - "bucket_size_duration", &lc_cfg->bucket_size_dur); - if (bucket_size_duration.parse(q["logical_channel_config"])) { - ERROR("Error can't find bucket_size_duration in section logical_channel_config\n"); - } + mbsfn_notification_config.add_field( + new parser::field("mbsfn_notification_offset", &data->notif_cfg_r9.notif_offset_r9)); - parser::field log_chan_group("log_chan_group", &lc_cfg->lc_ch_group); - lc_cfg->lc_ch_group_present = not log_chan_group.parse(q["logical_channel_config"]); - cfg[qci].configured = true; - } + mbsfn_notification_config.add_field( + new parser::field("mbsfn_notification_sf_index", &data->notif_cfg_r9.notif_sf_idx_r9)); - return 0; -} + sib13.add_field(new mbsfn_area_info_list_parser(&data->mbsfn_area_info_list_r9, nullptr)); -namespace rr_sections { + return parser::parse_section(std::move(filename), &sib13); +} -static int parse_meas_cell_list(rrc_meas_cfg_t* meas_cfg, Setting& root) +int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_config_common) { - meas_cfg->meas_cells.resize(root.getLength()); - for (uint32_t i = 0; i < meas_cfg->meas_cells.size(); ++i) { - meas_cfg->meas_cells[i].earfcn = root[i]["dl_earfcn"]; - meas_cfg->meas_cells[i].pci = (unsigned int)root[i]["pci"] % 504; - meas_cfg->meas_cells[i].eci = (unsigned int)root[i]["eci"]; - meas_cfg->meas_cells[i].q_offset = 0; // LIBLTE_RRC_Q_OFFSET_RANGE_DB_0; // TODO - // // FIXME: TEMP - // printf("PARSER: neighbor cell: {dl_earfcn=%d pci=%d cell_idx=0x%x}\n", - // meas_cfg->meas_cells[i].earfcn, - // meas_cfg->meas_cells[i].pci, - // meas_cfg->meas_cells[i].eci); + // FIXME: Leave 0 blank for now + 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_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(); + + sib_type1_s* sib1 = &rrc_cfg_->sib1; + if (sib_sections::parse_sib1(args_->enb_files.sib_config, sib1) != SRSLTE_SUCCESS) { + return SRSLTE_ERROR; } - return 0; -} -static int parse_meas_report_desc(rrc_meas_cfg_t* meas_cfg, Setting& root) -{ - // NOTE: For now, only support one meas_report for all cells. - // TODO: for a1 - // TODO: for a2 - // meas report parsing - meas_cfg->meas_reports.resize(1); - asn1::rrc::report_cfg_eutra_s& meas_item = meas_cfg->meas_reports[0]; - HANDLEPARSERCODE(asn1_parsers::str_to_enum(meas_item.trigger_quant, root["a3_report_type"])); - auto& event = meas_item.trigger_type.set_event(); - event.event_id.set_event_a3().report_on_leave = false; - event.event_id.event_a3().a3_offset = (int)root["a3_offset"]; - event.hysteresis = (int)root["a3_hysteresis"]; - meas_item.max_report_cells = 1; // TODO: parse - meas_item.report_amount.value = report_cfg_eutra_s::report_amount_e_::r1; // TODO: parse - meas_item.report_interv.value = report_interv_e::ms120; // TODO: parse - meas_item.report_quant.value = report_cfg_eutra_s::report_quant_opts::both; // TODO: parse - // quant coeff parsing - auto& quant = meas_cfg->quant_cfg; - HANDLEPARSERCODE(asn1_parsers::number_to_enum(event.time_to_trigger, root["a3_time_to_trigger"])); - HANDLEPARSERCODE( - asn1_parsers::opt_number_to_enum(quant.filt_coef_rsrp, quant.filt_coef_rsrp_present, root, "rsrp_config")); - HANDLEPARSERCODE( - asn1_parsers::opt_number_to_enum(quant.filt_coef_rsrq, quant.filt_coef_rsrq_present, root, "rsrq_config")); + // Fill rest of data from enb config + sib_type1_s::cell_access_related_info_s_* cell_access = &sib1->cell_access_related_info; + cell_access->cell_id.from_number((args_->stack.s1ap.enb_id << 8u) + args_->stack.s1ap.cell_id); + cell_access->tac.from_number(args_->stack.s1ap.tac); + sib1->freq_band_ind = (uint8_t)srslte_band_get_band(args_->enb.dl_earfcn); + std::string mnc_str; + if (not srslte::mnc_to_string(args_->stack.s1ap.mnc, &mnc_str)) { + ERROR("The provided mnc=%d is not valid", args_->stack.s1ap.mnc); + return -1; + } + std::string mcc_str; + if (not srslte::mcc_to_string(args_->stack.s1ap.mcc, &mcc_str)) { + ERROR("The provided mnc=%d is not valid", args_->stack.s1ap.mcc); + return -1; + } + cell_access->plmn_id_list.resize(1); + srslte::plmn_id_t plmn; + if (plmn.from_string(mcc_str + mnc_str) == SRSLTE_ERROR) { + ERROR("Could not convert %s to a plmn_id\n", (mcc_str + mnc_str).c_str()); + return -1; + } + srslte::to_asn1(&cell_access->plmn_id_list[0].plmn_id, plmn); + cell_access->plmn_id_list[0].cell_reserved_for_oper = plmn_id_info_s::cell_reserved_for_oper_e_::not_reserved; + sib1->cell_sel_info.q_rx_lev_min_offset = 0; - return SRSLTE_SUCCESS; -} + // Generate SIB2 + if (sib_sections::parse_sib2(args_->enb_files.sib_config, sib2) != SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } -static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root) -{ - auto cell_id_parser = [](uint32_t& cell_id, Setting& root) { return parse_bounded_number(cell_id, root, 0u, 255u); }; - uint32_t self_cellid = args->stack.s1ap.cell_id & 0xFFu; + // SRS not yet supported + sib2->rr_cfg_common.srs_ul_cfg_common.set(srs_ul_cfg_common_c::types::release); + if (sib2->freq_info.ul_bw_present) { + asn1::number_to_enum(sib2->freq_info.ul_bw, args_->enb.n_prb); + } + if (sib2->freq_info.ul_carrier_freq_present) { + sib2->freq_info.ul_carrier_freq = (uint16_t)args_->enb.ul_earfcn; + } - rrc_cfg->cell_list.resize(root.getLength()); - for (uint32_t n = 0; n < rrc_cfg->cell_list.size(); ++n) { - cell_cfg_t& cell_cfg = rrc_cfg->cell_list[n]; - auto& cellroot = root[n]; + // Update MBSFN list counter. Only 1 supported + if (not args_->stack.embms.enable) { + sib2->mbsfn_sf_cfg_list_present = false; + sib2->mbsfn_sf_cfg_list.resize(0); + } else { + // verify SIB13 is available + if (not sib_is_present(sib1->sched_info_list, sib_type_e::sib_type13_v920)) { + fprintf(stderr, "SIB13 not present in sched_info.\n"); + return -1; + } + } - parse_opt_field(cell_cfg.rf_port, cellroot, "rf_port"); - parse_default_field(cell_cfg.cell_id, cellroot, "cell_id", self_cellid, cell_id_parser); - parse_default_field(cell_cfg.tac, cellroot, "tac", args->stack.s1ap.tac); - parse_default_field(cell_cfg.pci, cellroot, "pci", args->enb.pci); - parse_default_field( - cell_cfg.root_seq_idx, cellroot, "root_seq_idx", rrc_cfg->sibs[1].sib2().rr_cfg_common.prach_cfg.root_seq_idx); - parse_default_field(cell_cfg.dl_earfcn, cellroot, "dl_earfcn", args->enb.dl_earfcn); - parse_default_field(cell_cfg.ul_earfcn, cellroot, "ul_earfcn", args->enb.ul_earfcn); + // Generate SIB3 if defined in mapping info + if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type3)) { + if (sib_sections::parse_sib3(args_->enb_files.sib_config, sib3) != SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + } - if (cellroot["ho_active"]) { - HANDLEPARSERCODE(parse_meas_cell_list(&rrc_cfg->meas_cfg, cellroot["meas_cell_list"])); - HANDLEPARSERCODE(parse_meas_report_desc(&rrc_cfg->meas_cfg, cellroot["meas_report_desc"])); + // Generate SIB4 if defined in mapping info + if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type4)) { + if (sib_sections::parse_sib4(args_->enb_files.sib_config, sib4) != SRSLTE_SUCCESS) { + return SRSLTE_ERROR; } + } - cell_cfg.scell_list.resize(cellroot["scell_list"].getLength()); - for (uint32_t i = 0; i < cell_cfg.scell_list.size(); ++i) { - auto& scell = cell_cfg.scell_list[i]; - auto& scellroot = cellroot["scell_list"][i]; - cell_id_parser(scell.cell_id, scellroot["cell_id"]); - scell.cross_carrier_sched = (bool)scellroot["cross_carrier_scheduling"]; - cell_id_parser(scell.sched_cell_id, scellroot["scheduling_cell_id"]); - scell.ul_allowed = (bool)scellroot["ul_allowed"]; + // 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) != SRSLTE_SUCCESS) { + return SRSLTE_ERROR; } } - // Configuration check - for (auto it = rrc_cfg->cell_list.begin(); it != rrc_cfg->cell_list.end(); it++) { - for (auto it2 = it + 1; it2 != rrc_cfg->cell_list.end(); it2++) { - // Check RF port is not repeated - if (it->rf_port == it2->rf_port) { - ERROR("Repeated RF port for multiple cells\n"); - } + // Generate SIB9 if defined in mapping info + if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type9)) { + if (sib_sections::parse_sib9(args_->enb_files.sib_config, sib9) != SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + } - // Check cell ID is not repeated - if (it->cell_id == it2->cell_id) { - ERROR("Repeated Cell identifier\n"); - } + if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type13_v920)) { + if (sib_sections::parse_sib13(args_->enb_files.sib_config, sib13) != SRSLTE_SUCCESS) { + return SRSLTE_ERROR; } } - return SRSLTE_SUCCESS; + // Copy PHY common configuration + phy_config_common->cell = {}; + phy_config_common->prach_cnfg = sib2->rr_cfg_common.prach_cfg; + phy_config_common->pdsch_cnfg = sib2->rr_cfg_common.pdsch_cfg_common; + phy_config_common->pusch_cnfg = sib2->rr_cfg_common.pusch_cfg_common; + phy_config_common->pucch_cnfg = sib2->rr_cfg_common.pucch_cfg_common; + phy_config_common->srs_ul_cnfg = sib2->rr_cfg_common.srs_ul_cfg_common; + + return 0; } -int cell_list_section::parse(libconfig::Setting& root) +} // namespace sib_sections + +namespace drb_sections { + +int parse_drb(all_args_t* args_, rrc_cfg_t* rrc_cfg_) { - HANDLEPARSERCODE(parse_cell_list(args, rrc_cfg, root)); - return 0; + parser::section qci("qci_config"); + qci.add_field(new field_qci(rrc_cfg_->qci_cfg)); + return parser::parse_section(args_->enb_files.drb_config, &qci); } -} // namespace rr_sections +} // namespace drb_sections } // namespace srsenb diff --git a/srsenb/src/enb_cfg_parser.h b/srsenb/src/enb_cfg_parser.h index a8bea8fab..c268e6725 100644 --- a/srsenb/src/enb_cfg_parser.h +++ b/srsenb/src/enb_cfg_parser.h @@ -37,7 +37,61 @@ namespace srsenb { using namespace libconfig; -class all_args_t; +struct all_args_t; +struct phy_cfg_t; + +bool sib_is_present(const asn1::rrc::sched_info_list_l& l, asn1::rrc::sib_type_e sib_num); + +// enb.conf parsing +namespace enb_conf_sections { + +int parse_cell_cfg(all_args_t* args_, srslte_cell_t* cell); +int parse_cfg_files(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_); +int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_, srslte_cell_t* cell_cfg_); + +} // namespace enb_conf_sections + +// sib.conf parsing +namespace sib_sections { + +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_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); +int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_config_common); + +} // namespace sib_sections + +// drb.conf parsing +namespace drb_sections { + +int parse_drb(all_args_t* args, rrc_cfg_t* rrc_cfg); +} // namespace drb_sections + +// rr.conf parsing +namespace rr_sections { + +int parse_rr(all_args_t* args_, rrc_cfg_t* rrc_cfg_); + +// rrc_cnfg +class cell_list_section final : public parser::field_itf +{ +public: + explicit cell_list_section(all_args_t* all_args_, rrc_cfg_t* rrc_cfg_) : args(all_args_), rrc_cfg(rrc_cfg_) {} + + int parse(Setting& root) override; + + const char* get_name() override { return "meas_cell_list"; } + +private: + rrc_cfg_t* rrc_cfg; + all_args_t* args; +}; + +} // namespace rr_sections class field_sched_info final : public parser::field_itf { @@ -111,26 +165,6 @@ private: rrc_cfg_qci_t* cfg; }; -namespace rr_sections { - -// rrc_cnfg - -class cell_list_section final : public parser::field_itf -{ -public: - explicit cell_list_section(all_args_t* all_args_, rrc_cfg_t* rrc_cfg_) : args(all_args_), rrc_cfg(rrc_cfg_) {} - - int parse(Setting& root) override; - - const char* get_name() override { return "meas_cell_list"; } - -private: - rrc_cfg_t* rrc_cfg; - all_args_t* args; -}; - -} // namespace rr_sections - // ASN1 parsers class field_asn1 : public parser::field_itf diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index 000d49541..fa71806d3 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -45,15 +45,15 @@ rrc::rrc() : cnotifier(nullptr), nof_si_messages(0) rrc::~rrc() {} -void rrc::init(rrc_cfg_t* cfg_, - phy_interface_stack_lte* phy_, - mac_interface_rrc* mac_, - rlc_interface_rrc* rlc_, - pdcp_interface_rrc* pdcp_, - s1ap_interface_rrc* s1ap_, - gtpu_interface_rrc* gtpu_, - srslte::timer_handler* timers_, - srslte::log* log_rrc) +void rrc::init(rrc_cfg_t* cfg_, + phy_interface_rrc_lte* phy_, + mac_interface_rrc* mac_, + rlc_interface_rrc* rlc_, + pdcp_interface_rrc* pdcp_, + s1ap_interface_rrc* s1ap_, + gtpu_interface_rrc* gtpu_, + srslte::timer_handler* timers_, + srslte::log* log_rrc) { phy = phy_; mac = mac_; @@ -1208,9 +1208,10 @@ void rrc::ue::parse_ul_dcch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) } break; case ul_dcch_msg_type_c::c1_c_::types::meas_report: - printf("Received MEASUREMENT REPORT!\n"); if (mobility_handler != nullptr) { mobility_handler->handle_ue_meas_report(ul_dcch_msg.msg.c1().meas_report()); + } else { + parent->rrc_log->warning("Received MeasReport but no mobility configuration is available\n"); } break; default: diff --git a/srsenb/test/common/dummy_classes.h b/srsenb/test/common/dummy_classes.h new file mode 100644 index 000000000..7f5c21e10 --- /dev/null +++ b/srsenb/test/common/dummy_classes.h @@ -0,0 +1,112 @@ +/* + * 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_DUMMY_CLASSES_H +#define SRSLTE_DUMMY_CLASSES_H + +#include "srslte/interfaces/enb_interfaces.h" + +namespace srsenb { + +class rlc_dummy : public rlc_interface_rrc +{ +public: + void clear_buffer(uint16_t rnti) override {} + void add_user(uint16_t rnti) override {} + void rem_user(uint16_t rnti) override {} + void add_bearer(uint16_t rnti, uint32_t lcid, srslte::rlc_config_t cnfg) override {} + void add_bearer_mrb(uint16_t rnti, uint32_t lcid) override {} + void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) override {} + bool has_bearer(uint16_t rnti, uint32_t lcid) override { return false; } +}; + +class pdcp_dummy : public pdcp_interface_rrc +{ +public: + void reset(uint16_t rnti) override {} + void add_user(uint16_t rnti) override {} + void rem_user(uint16_t rnti) override {} + void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) override {} + void add_bearer(uint16_t rnti, uint32_t lcid, srslte::pdcp_config_t cnfg) override {} + void config_security(uint16_t rnti, + uint32_t lcid, + uint8_t* k_rrc_enc_, + uint8_t* k_rrc_int_, + uint8_t* k_up_enc_, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) override + { + } + void enable_integrity(uint16_t rnti, uint32_t lcid) override {} + void enable_encryption(uint16_t rnti, uint32_t lcid) override {} +}; + +class s1ap_dummy : public s1ap_interface_rrc +{ +public: + void + initial_ue(uint16_t rnti, LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM cause, srslte::unique_byte_buffer_t pdu) override + { + } + void initial_ue(uint16_t rnti, + LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM cause, + srslte::unique_byte_buffer_t pdu, + uint32_t m_tmsi, + uint8_t mmec) override + { + } + + void write_pdu(uint16_t rnti, srslte::unique_byte_buffer_t pdu) override {} + bool user_exists(uint16_t rnti) override { return true; } + bool user_release(uint16_t rnti, LIBLTE_S1AP_CAUSERADIONETWORK_ENUM cause_radio) override { return true; } + void ue_ctxt_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT* res) override {} + void ue_erab_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT* res) override {} + bool is_mme_connected() override { return true; } + bool send_ho_required(uint16_t rnti, + uint32_t target_eci, + srslte::plmn_id_t target_plmn, + srslte::unique_byte_buffer_t rrc_container) override + { + return true; + } +}; + +class phy_dummy : public phy_interface_rrc_lte +{ +public: + void + configure_mbsfn(asn1::rrc::sib_type2_s* sib2, asn1::rrc::sib_type13_r9_s* sib13, asn1::rrc::mcch_msg_s mcch) override + { + } + void set_config_dedicated(uint16_t rnti, asn1::rrc::phys_cfg_ded_s* dedicated) override {} +}; + +class gtpu_dummy : public gtpu_interface_rrc +{ +public: + void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t* teid_in) {} + void rem_bearer(uint16_t rnti, uint32_t lcid) {} + void rem_user(uint16_t rnti) {} +}; + +} // namespace srsenb + +#endif // SRSLTE_DUMMY_CLASSES_H diff --git a/srsenb/test/upper/CMakeLists.txt b/srsenb/test/upper/CMakeLists.txt index 6becf341f..9a4797348 100644 --- a/srsenb/test/upper/CMakeLists.txt +++ b/srsenb/test/upper/CMakeLists.txt @@ -23,4 +23,6 @@ add_executable(plmn_test plmn_test.cc) target_link_libraries(plmn_test rrc_asn1) add_executable(rrc_mobility_test rrc_mobility_test.cc) -target_link_libraries(rrc_mobility_test srsenb_rrc rrc_asn1 srslte_common srslte_asn1) \ No newline at end of file +target_link_libraries(rrc_mobility_test srsenb_rrc rrc_asn1 srslte_common srslte_asn1 enb_cfg_parser ${LIBCONFIGPP_LIBRARIES}) + +add_test(rrc_mobility_test rrc_mobility_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..) diff --git a/srsenb/test/upper/rrc_mobility_test.cc b/srsenb/test/upper/rrc_mobility_test.cc index afb71770e..1d228d2c8 100644 --- a/srsenb/test/upper/rrc_mobility_test.cc +++ b/srsenb/test/upper/rrc_mobility_test.cc @@ -19,7 +19,10 @@ * */ +#include "srsenb/hdr/enb.h" #include "srsenb/hdr/stack/rrc/rrc_mobility.h" +#include "srsenb/src/enb_cfg_parser.h" +#include "srsenb/test/common/dummy_classes.h" #include "srslte/asn1/rrc_asn1_utils.h" #include "srslte/common/test_common.h" #include @@ -28,7 +31,67 @@ using namespace srsenb; using namespace asn1::rrc; -srslte::log_filter log_h("ALL"); +srslte::scoped_tester_log log_h("ALL"); + +namespace argparse { + +std::string repository_dir; +srslte::LOG_LEVEL_ENUM log_level; + +void usage(char* prog) +{ + printf("Usage: %s [v] -i repository_dir\n", prog); + printf("\t-v [set srslte_verbose to debug, default none]\n"); +} + +void parse_args(int argc, char** argv) +{ + int opt; + + while ((opt = getopt(argc, argv, "i")) != -1) { + switch (opt) { + case 'i': + repository_dir = argv[optind]; + break; + case 'v': + log_level = srslte::LOG_LEVEL_DEBUG; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (repository_dir.empty()) { + usage(argv[0]); + exit(-1); + } +} + +} // namespace argparse + +namespace test_dummies { + +class s1ap_mobility_dummy : public s1ap_dummy +{ +public: + struct ho_req_data { + uint16_t rnti; + uint32_t target_eci; + srslte::plmn_id_t target_plmn; + srslte::unique_byte_buffer_t rrc_container; + } last_ho_required; + + bool send_ho_required(uint16_t rnti, + uint32_t target_eci, + srslte::plmn_id_t target_plmn, + srslte::unique_byte_buffer_t rrc_container) final + { + last_ho_required = ho_req_data{rnti, target_eci, target_plmn, std::move(rrc_container)}; + return true; + } +}; + +} // namespace test_dummies class mac_dummy : public mac_interface_rrc { @@ -254,61 +317,173 @@ int test_correct_meascfg_calculation() return SRSLTE_SUCCESS; } -int test_mobility_class() +int parse_default_cfg(rrc_cfg_t* rrc_cfg, srsenb::all_args_t& args) { - srslte::scoped_tester_log log_test("MOBILITY_TEST"); - - rrc_cfg_t cfg; - cfg.sib1.cell_access_related_info.plmn_id_list.push_back({}); - cfg.sib1.cell_access_related_info.plmn_id_list[0].plmn_id.mnc.resize(2); - cfg.sib1.cell_access_related_info.plmn_id_list[0].cell_reserved_for_oper.value = - plmn_id_info_s::cell_reserved_for_oper_opts::not_reserved; - cfg.sib1.cell_access_related_info.cell_barred.value = - sib_type1_s::cell_access_related_info_s_::cell_barred_opts::not_barred; - cfg.sib1.cell_access_related_info.intra_freq_resel.value = - sib_type1_s::cell_access_related_info_s_::intra_freq_resel_opts::allowed; - cfg.sib1.si_win_len.value = sib_type1_s::si_win_len_opts::ms5; - cfg.sib1.sched_info_list.push_back({}); - cfg.sib1.sched_info_list[0].si_periodicity.value = sched_info_s::si_periodicity_opts::rf8; - auto& sib2 = cfg.sibs[1].set_sib2(); - sib2.rr_cfg_common.rach_cfg_common.preamb_info.nof_ra_preambs.value = - rach_cfg_common_s::preamb_info_s_::nof_ra_preambs_opts::n4; - sib2.rr_cfg_common.rach_cfg_common.pwr_ramp_params.pwr_ramp_step.value = pwr_ramp_params_s::pwr_ramp_step_opts::db0; - sib2.rr_cfg_common.rach_cfg_common.pwr_ramp_params.preamb_init_rx_target_pwr.value = - pwr_ramp_params_s::preamb_init_rx_target_pwr_opts::dbm_minus90; - sib2.rr_cfg_common.rach_cfg_common.ra_supervision_info.preamb_trans_max.value = preamb_trans_max_opts::n4; - sib2.rr_cfg_common.rach_cfg_common.ra_supervision_info.ra_resp_win_size.value = - rach_cfg_common_s::ra_supervision_info_s_::ra_resp_win_size_opts::sf2; - sib2.rr_cfg_common.rach_cfg_common.ra_supervision_info.mac_contention_resolution_timer.value = - rach_cfg_common_s::ra_supervision_info_s_::mac_contention_resolution_timer_opts::sf8; - sib2.rr_cfg_common.bcch_cfg.mod_period_coeff.value = bcch_cfg_s::mod_period_coeff_opts::n4; - sib2.rr_cfg_common.pcch_cfg.default_paging_cycle.value = pcch_cfg_s::default_paging_cycle_opts::rf32; - sib2.rr_cfg_common.pcch_cfg.nb.value = pcch_cfg_s::nb_opts::four_t; - sib2.rr_cfg_common.pusch_cfg_common.pusch_cfg_basic.hop_mode.value = - pusch_cfg_common_s::pusch_cfg_basic_s_::hop_mode_opts::inter_sub_frame; - sib2.rr_cfg_common.pucch_cfg_common.delta_pucch_shift.value = pucch_cfg_common_s::delta_pucch_shift_opts::ds1; - sib2.rr_cfg_common.srs_ul_cfg_common.set(setup_opts::release); - sib2.rr_cfg_common.ul_pwr_ctrl_common.alpha.value = alpha_r12_opts::al0; - bzero(&sib2.rr_cfg_common.ul_pwr_ctrl_common.delta_flist_pucch, - sizeof(sib2.rr_cfg_common.ul_pwr_ctrl_common.delta_flist_pucch)); - sib2.rr_cfg_common.ul_cp_len.value = ul_cp_len_opts::len1; - bzero(&sib2.ue_timers_and_consts, sizeof(sib2.ue_timers_and_consts)); - sib2.time_align_timer_common.value = time_align_timer_opts::sf500; - report_cfg_eutra_s rep = generate_rep1(); + args = {}; + *rrc_cfg = {}; + args.enb_files.sib_config = argparse::repository_dir + "/sib.conf.example"; + args.enb_files.rr_config = argparse::repository_dir + "/rr.conf.example"; + args.enb_files.drb_config = argparse::repository_dir + "/drb.conf.example"; + log_h.debug("sib file path=%s\n", args.enb_files.sib_config.c_str()); + + args.enb.dl_earfcn = 3400; + args.enb.n_prb = 50; + TESTASSERT(srslte::string_to_mcc("001", &args.stack.s1ap.mcc)); + TESTASSERT(srslte::string_to_mnc("01", &args.stack.s1ap.mnc)); + args.enb.transmission_mode = 1; + args.enb.nof_ports = 1; + args.general.eia_pref_list = "EIA2, EIA1, EIA0"; + args.general.eea_pref_list = "EEA0, EEA2, EEA1"; + + phy_cfg_t phy_cfg; + + return enb_conf_sections::parse_cfg_files(&args, rrc_cfg, &phy_cfg); +} + +struct mobility_test_params { + enum class test_fail_at { never, wrong_measreport } fail_at; +}; + +int test_mobility_class(mobility_test_params test_params) +{ + log_h.info("----- TEST: test_mobility_class() -----\n"); + srslte::log_filter s1ap_log("S1AP"); + srslte::scoped_tester_log rrc_log("RRC "); + srslte::timer_handler timers; + srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance(); + srslte::unique_byte_buffer_t pdu; + + auto copy_msg_to_buffer = [pool](srslte::unique_byte_buffer_t& pdu, uint8_t* msg, size_t nof_bytes) { + pdu = srslte::allocate_unique_buffer(*pool, true); + memcpy(pdu->msg, msg, nof_bytes); + pdu->N_bytes = nof_bytes; + }; + + srsenb::all_args_t args; + rrc_cfg_t cfg; + TESTASSERT(parse_default_cfg(&cfg, args) == SRSLTE_SUCCESS); + report_cfg_eutra_s rep = generate_rep1(); cfg.meas_cfg.meas_reports.push_back(rep); + meas_cell_cfg_t cell2 = generate_cell1(); + cell2.pci = 2; + cell2.eci = 0x19C02; + cfg.meas_cfg.meas_cells.push_back(cell2); + + srsenb::rrc rrc; + mac_dummy mac; + rlc_dummy rlc; + pdcp_dummy pdcp; + phy_dummy phy; + test_dummies::s1ap_mobility_dummy s1ap; + gtpu_dummy gtpu; + rrc_log.set_level(srslte::LOG_LEVEL_INFO); + rrc_log.set_hex_limit(1024); + s1ap_log.set_level(srslte::LOG_LEVEL_INFO); + s1ap_log.set_hex_limit(1024); + rrc.init(&cfg, &phy, &mac, &rlc, &pdcp, &s1ap, >pu, &timers, &rrc_log); + + auto tic = [&timers, &rrc] { + timers.step_all(); + rrc.tti_clock(); + }; + + uint16_t rnti = 0x46; + rrc.add_user(rnti); + + // Send RRCConnectionRequest + uint8_t rrc_conn_request[] = {0x40, 0x12, 0xf6, 0xfb, 0xe2, 0xc6}; + copy_msg_to_buffer(pdu, rrc_conn_request, sizeof(rrc_conn_request)); + rrc.write_pdu(rnti, 0, std::move(pdu)); + tic(); + + // Send RRCConnectionSetupComplete + uint8_t rrc_conn_setup_complete[] = {0x20, 0x00, 0x40, 0x2e, 0x90, 0x50, 0x49, 0xe8, 0x06, 0x0e, 0x82, 0xa2, + 0x17, 0xec, 0x13, 0xe2, 0x0f, 0x00, 0x02, 0x02, 0x5e, 0xdf, 0x7c, 0x58, + 0x05, 0xc0, 0xc0, 0x00, 0x08, 0x04, 0x03, 0xa0, 0x23, 0x23, 0xc0}; + copy_msg_to_buffer(pdu, rrc_conn_setup_complete, sizeof(rrc_conn_setup_complete)); + rrc.write_pdu(rnti, 1, std::move(pdu)); + tic(); + + // S1AP receives InitialContextSetupRequest and forwards it to RRC + uint8_t s1ap_init_ctxt_setup_req[] = { + 0x00, 0x09, 0x00, 0x80, 0xc6, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x42, 0x00, 0x0a, 0x18, 0x3b, 0x9a, 0xca, 0x00, 0x60, 0x3b, 0x9a, 0xca, 0x00, 0x00, 0x18, 0x00, 0x78, + 0x00, 0x00, 0x34, 0x00, 0x73, 0x45, 0x00, 0x09, 0x3c, 0x0f, 0x80, 0x0a, 0x00, 0x21, 0xf0, 0xb7, 0x36, 0x1c, 0x56, + 0x64, 0x27, 0x3e, 0x5b, 0x04, 0xb7, 0x02, 0x07, 0x42, 0x02, 0x3e, 0x06, 0x00, 0x09, 0xf1, 0x07, 0x00, 0x07, 0x00, + 0x37, 0x52, 0x66, 0xc1, 0x01, 0x09, 0x1b, 0x07, 0x74, 0x65, 0x73, 0x74, 0x31, 0x32, 0x33, 0x06, 0x6d, 0x6e, 0x63, + 0x30, 0x37, 0x30, 0x06, 0x6d, 0x63, 0x63, 0x39, 0x30, 0x31, 0x04, 0x67, 0x70, 0x72, 0x73, 0x05, 0x01, 0xc0, 0xa8, + 0x03, 0x02, 0x27, 0x0e, 0x80, 0x80, 0x21, 0x0a, 0x03, 0x00, 0x00, 0x0a, 0x81, 0x06, 0x08, 0x08, 0x08, 0x08, 0x50, + 0x0b, 0xf6, 0x09, 0xf1, 0x07, 0x80, 0x01, 0x01, 0xf6, 0x7e, 0x72, 0x69, 0x13, 0x09, 0xf1, 0x07, 0x00, 0x01, 0x23, + 0x05, 0xf4, 0xf6, 0x7e, 0x72, 0x69, 0x00, 0x6b, 0x00, 0x05, 0x18, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x20, + 0x45, 0x25, 0xe4, 0x9a, 0x77, 0xc8, 0xd5, 0xcf, 0x26, 0x33, 0x63, 0xeb, 0x5b, 0xb9, 0xc3, 0x43, 0x9b, 0x9e, 0xb3, + 0x86, 0x1f, 0xa8, 0xa7, 0xcf, 0x43, 0x54, 0x07, 0xae, 0x42, 0x2b, 0x63, 0xb9}; + LIBLTE_S1AP_S1AP_PDU_STRUCT s1ap_pdu; + LIBLTE_BYTE_MSG_STRUCT byte_buf; + byte_buf.N_bytes = sizeof(s1ap_init_ctxt_setup_req); + memcpy(byte_buf.msg, s1ap_init_ctxt_setup_req, byte_buf.N_bytes); + liblte_s1ap_unpack_s1ap_pdu(&byte_buf, &s1ap_pdu); + rrc.setup_ue_ctxt(rnti, &s1ap_pdu.choice.initiatingMessage.choice.InitialContextSetupRequest); + tic(); + + // Send SecurityModeComplete + uint8_t sec_mode_complete[] = {0x28, 0x00}; + copy_msg_to_buffer(pdu, sec_mode_complete, sizeof(sec_mode_complete)); + rrc.write_pdu(rnti, 1, std::move(pdu)); + tic(); + + /* Receive MeasReport from UE (correct if PCI=2) */ + if (test_params.fail_at == mobility_test_params::test_fail_at::wrong_measreport) { + uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x0D, 0xBC, 0x80}; // PCI == 3 + copy_msg_to_buffer(pdu, meas_report, sizeof(meas_report)); + } else { + uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x09, 0xBC, 0x80}; // PCI == 2 + copy_msg_to_buffer(pdu, meas_report, sizeof(meas_report)); + } + rrc.write_pdu(rnti, 1, std::move(pdu)); + tic(); - srsenb::rrc rrc; - mac_dummy mac; - // rrc.init(&cfg, nullptr, &mac, nullptr, nullptr, nullptr, nullptr, &log_h); + if (test_params.fail_at == mobility_test_params::test_fail_at::wrong_measreport) { + TESTASSERT(s1ap.last_ho_required.rrc_container == nullptr); + TESTASSERT(rrc_log.error_counter == 1); + return SRSLTE_SUCCESS; + } + + // Check HO Required was sent to S1AP + TESTASSERT(s1ap.last_ho_required.rnti == rnti); + TESTASSERT(s1ap.last_ho_required.target_eci == cell2.eci); + TESTASSERT(s1ap.last_ho_required.target_plmn.to_string() == "00101"); + { + asn1::bit_ref bref(s1ap.last_ho_required.rrc_container->msg, s1ap.last_ho_required.rrc_container->N_bytes); + asn1::rrc::ho_prep_info_s hoprep; + TESTASSERT(hoprep.unpack(bref) == asn1::SRSASN_SUCCESS); + ho_prep_info_r8_ies_s& hoprepr8 = hoprep.crit_exts.c1().ho_prep_info_r8(); + TESTASSERT(hoprepr8.as_cfg_present); + // Check if RRC sends the current active bearers + TESTASSERT(hoprepr8.as_cfg.source_rr_cfg.drb_to_add_mod_list_present); + TESTASSERT(hoprepr8.as_cfg.source_rr_cfg.drb_to_add_mod_list[0].drb_id == 1); + } + // MME returns back an HandoverCommand + // TODO + + TESTASSERT(rrc_log.error_counter == 0); return SRSLTE_SUCCESS; } -int main() +int main(int argc, char** argv) { + log_h.set_level(srslte::LOG_LEVEL_INFO); + + if (argc < 3) { + argparse::usage(argv[0]); + return -1; + } + argparse::parse_args(argc, argv); + TESTASSERT(test_correct_insertion() == 0); TESTASSERT(test_correct_meascfg_calculation() == 0); - TESTASSERT(test_mobility_class() == 0); + TESTASSERT(test_mobility_class(mobility_test_params{mobility_test_params::test_fail_at::never}) == 0); + TESTASSERT(test_mobility_class(mobility_test_params{mobility_test_params::test_fail_at::wrong_measreport}) == 0); printf("Success\n");