/** * * \section COPYRIGHT * * Copyright 2013-2017 Software Radio Systems Limited * * \section LICENSE * * This file is part of srsLTE. * * srsUE 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. * * srsUE 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/. * */ #include "srslte/asn1/liblte_common.h" #include "srslte/asn1/liblte_rrc.h" #include "cfg_parser.h" #include "srslte/srslte.h" #include "parser.h" #include "enb_cfg_parser.h" namespace srsenb { int enb::parse_cell_cfg(all_args_t *args, srslte_cell_t *cell) { cell->id = args->enb.pci; cell->cp = SRSLTE_CP_NORM; cell->nof_ports = args->enb.nof_ports; cell->nof_prb = args->enb.n_prb; LIBLTE_RRC_PHICH_CONFIG_STRUCT phichcfg; parser::section phy_cnfg("phy_cnfg"); parser::section phich_cnfg("phich_cnfg"); phy_cnfg.add_subsection(&phich_cnfg); phich_cnfg.add_field( new parser::field_enum_str ("duration", &phichcfg.dur, liblte_rrc_phich_duration_text, LIBLTE_RRC_PHICH_DURATION_N_ITEMS) ); phich_cnfg.add_field( new parser::field_enum_str ("resources", &phichcfg.res, liblte_rrc_phich_resource_text, LIBLTE_RRC_PHICH_RESOURCE_N_ITEMS) ); parser::parse_section(args->enb_files.rr_config, &phy_cnfg); cell->phich_length = (srslte_phich_length_t) (int) phichcfg.dur; cell->phich_resources = (srslte_phich_resources_t) (int) phichcfg.res; if (!srslte_cell_isvalid(cell)) { fprintf(stderr, "Invalid cell parameters: nof_prb=%d, cell_id=%d\n", args->enb.n_prb, args->enb.s1ap.cell_id); return -1; } return 0; } int field_sched_info::parse(libconfig::Setting &root) { data->N_sched_info = root.getLength(); for (uint32_t i=0;iN_sched_info;i++) { uint32_t periodicity = 0; if (!root[i].lookupValue("si_periodicity", periodicity)) { fprintf(stderr, "Missing field si_periodicity in sched_info=%d\n", i); return -1; } int k=0; while(ksched_info[i].si_periodicity = (LIBLTE_RRC_SI_PERIODICITY_ENUM) k; if (root[i].exists("si_mapping_info")) { data->sched_info[i].N_sib_mapping_info = root[i]["si_mapping_info"].getLength(); if (data->sched_info[i].N_sib_mapping_info < LIBLTE_RRC_MAX_SIB) { for (uint32_t j=0;jsched_info[i].N_sib_mapping_info;j++) { uint32_t sib_index = root[i]["si_mapping_info"][j]; if (sib_index >= 3 && sib_index <= 13) { data->sched_info[i].sib_mapping_info[j].sib_type = (LIBLTE_RRC_SIB_TYPE_ENUM) (sib_index-3); } else { fprintf(stderr, "Invalid SIB index %d for si_mapping_info=%d in sched_info=%d\n", sib_index, j, i); return -1; } } } else { fprintf(stderr, "Number of si_mapping_info values exceeds maximum (%d)\n", LIBLTE_RRC_MAX_SIB); return -1; } } else { data->sched_info[i].N_sib_mapping_info = 0; } } return 0; } int field_intra_neigh_cell_list::parse(libconfig::Setting &root) { data->intra_freq_neigh_cell_list_size = root.getLength(); for (uint32_t i=0;iintra_freq_neigh_cell_list_size && iintra_freq_neigh_cell_list[i].q_offset_range = (LIBLTE_RRC_Q_OFFSET_RANGE_ENUM) k; int phys_cell_id = 0; if (!root[i].lookupValue("phys_cell_id", phys_cell_id)) { fprintf(stderr, "Missing field phys_cell_id in neigh_cell=%d\n", i); return -1; } data->intra_freq_neigh_cell_list[i].phys_cell_id = (uint16) phys_cell_id; } return 0; } int field_intra_black_cell_list::parse(libconfig::Setting &root) { data->intra_freq_black_cell_list_size = root.getLength(); for (uint32_t i=0;iintra_freq_black_cell_list_size && iintra_freq_black_cell_list[i].range = (LIBLTE_RRC_PHYS_CELL_ID_RANGE_ENUM) k; int start = 0; if (!root[i].lookupValue("start", start)) { fprintf(stderr, "Missing field start in black_cell=%d\n", i); return -1; } data->intra_freq_black_cell_list[i].start = (uint16) start; } return 0; } int enb::parse_sib1(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *data) { parser::section sib1("sib1"); sib1.add_field( new parser::field_enum_str ("intra_freq_reselection", &data->intra_freq_reselection, liblte_rrc_intra_freq_reselection_text, LIBLTE_RRC_INTRA_FREQ_RESELECTION_N_ITEMS) ); sib1.add_field( new parser::field("q_rx_lev_min", &data->q_rx_lev_min) ); sib1.add_field( new parser::field("p_max", &data->p_max, &data->p_max_present) ); sib1.add_field( new parser::field_enum_str ("cell_barred", &data->cell_barred, liblte_rrc_cell_barred_text, LIBLTE_RRC_CELL_BARRED_N_ITEMS) ); sib1.add_field( new parser::field_enum_num ("si_window_length", &data->si_window_length, liblte_rrc_si_window_length_num, LIBLTE_RRC_SI_WINDOW_LENGTH_N_ITEMS) ); sib1.add_field( new parser::field("system_info_value_tag", &data->system_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(filename, &sib1); } int enb::parse_sib2(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *data) { parser::section sib2("sib2"); sib2.add_field( new parser::field_enum_str ("time_alignment_timer", &data->time_alignment_timer, liblte_rrc_time_alignment_timer_text, LIBLTE_RRC_TIME_ALIGNMENT_TIMER_N_ITEMS) ); parser::section freqinfo("freqInfo"); sib2.add_subsection(&freqinfo); freqinfo.add_field( new parser::field ("additional_spectrum_emission", &data->additional_spectrum_emission) ); freqinfo.add_field( new parser::field ("ul_carrier_freq_present", &data->arfcn_value_eutra.present) ); freqinfo.add_field( new parser::field ("ul_bw_present", &data->ul_bw.present) ); // AC barring configuration parser::section acbarring("ac_barring"); sib2.add_subsection(&acbarring); acbarring.set_optional(&data->ac_barring_info_present); acbarring.add_field( new parser::field("ac_barring_for_emergency", &data->ac_barring_for_emergency) ); parser::section acbarring_signalling("ac_barring_for_mo_signalling"); acbarring.add_subsection(&acbarring_signalling); acbarring_signalling.set_optional(&data->ac_barring_for_mo_signalling.enabled); acbarring_signalling.add_field( new parser::field_enum_num ("factor", &data->ac_barring_for_mo_signalling.factor, liblte_rrc_ac_barring_factor_num, LIBLTE_RRC_AC_BARRING_FACTOR_N_ITEMS) ); acbarring_signalling.add_field( new parser::field_enum_num ("time", &data->ac_barring_for_mo_signalling.time, liblte_rrc_ac_barring_time_num, LIBLTE_RRC_AC_BARRING_FACTOR_N_ITEMS) ); acbarring_signalling.add_field( new parser::field("for_special_ac", &data->ac_barring_for_mo_signalling.for_special_ac) ); parser::section acbarring_data("ac_barring_for_mo_data"); acbarring.add_subsection(&acbarring_data); acbarring_data.set_optional(&data->ac_barring_for_mo_data.enabled); acbarring_data.add_field( new parser::field_enum_num ("factor", &data->ac_barring_for_mo_data.factor, liblte_rrc_ac_barring_factor_num, LIBLTE_RRC_AC_BARRING_FACTOR_N_ITEMS) ); acbarring_data.add_field( new parser::field_enum_num ("time", &data->ac_barring_for_mo_data.time, liblte_rrc_ac_barring_time_num, LIBLTE_RRC_AC_BARRING_FACTOR_N_ITEMS) ); acbarring_data.add_field( new parser::field("for_special_ac", &data->ac_barring_for_mo_data.for_special_ac) ); // UE timers and constants parser::section uetimers("ue_timers_and_constants"); sib2.add_subsection(&uetimers); uetimers.add_field( new parser::field_enum_num ("t300", &data->ue_timers_and_constants.t300, liblte_rrc_t300_num, LIBLTE_RRC_T300_N_ITEMS) ); uetimers.add_field( new parser::field_enum_num ("t301", &data->ue_timers_and_constants.t301, liblte_rrc_t301_num, LIBLTE_RRC_T301_N_ITEMS) ); uetimers.add_field( new parser::field_enum_num ("t310", &data->ue_timers_and_constants.t310, liblte_rrc_t310_num, LIBLTE_RRC_T310_N_ITEMS) ); uetimers.add_field( new parser::field_enum_num ("n310", &data->ue_timers_and_constants.n310, liblte_rrc_n310_num, LIBLTE_RRC_N310_N_ITEMS) ); uetimers.add_field( new parser::field_enum_num ("t311", &data->ue_timers_and_constants.t311, liblte_rrc_t311_num, LIBLTE_RRC_T311_N_ITEMS) ); uetimers.add_field( new parser::field_enum_num ("n311", &data->ue_timers_and_constants.n311, liblte_rrc_n311_num, LIBLTE_RRC_N311_N_ITEMS) ); // Radio-resource configuration section parser::section rr_config("rr_config_common_sib"); sib2.add_subsection(&rr_config); rr_config.add_field( new parser::field_enum_str ("ul_cp_length", &data->rr_config_common_sib.ul_cp_length, liblte_rrc_ul_cp_length_text, LIBLTE_RRC_UL_CP_LENGTH_N_ITEMS) ); // RACH configuration parser::section rach_cnfg("rach_cnfg"); rr_config.add_subsection(&rach_cnfg); rach_cnfg.add_field( new parser::field_enum_num ("num_ra_preambles", &data->rr_config_common_sib.rach_cnfg.num_ra_preambles, liblte_rrc_number_of_ra_preambles_num, LIBLTE_RRC_NUMBER_OF_RA_PREAMBLES_N_ITEMS) ); rach_cnfg.add_field( new parser::field_enum_num ("preamble_init_rx_target_pwr", &data->rr_config_common_sib.rach_cnfg.preamble_init_rx_target_pwr, liblte_rrc_preamble_initial_received_target_power_num, LIBLTE_RRC_PREAMBLE_INITIAL_RECEIVED_TARGET_POWER_N_ITEMS) ); rach_cnfg.add_field( new parser::field_enum_num ("pwr_ramping_step", &data->rr_config_common_sib.rach_cnfg.pwr_ramping_step, liblte_rrc_power_ramping_step_num, LIBLTE_RRC_POWER_RAMPING_STEP_N_ITEMS) ); rach_cnfg.add_field( new parser::field_enum_num ("preamble_trans_max", &data->rr_config_common_sib.rach_cnfg.preamble_trans_max, liblte_rrc_preamble_trans_max_num, LIBLTE_RRC_PREAMBLE_TRANS_MAX_N_ITEMS) ); rach_cnfg.add_field( new parser::field_enum_num ("ra_resp_win_size", &data->rr_config_common_sib.rach_cnfg.ra_resp_win_size, liblte_rrc_ra_response_window_size_num, LIBLTE_RRC_RA_RESPONSE_WINDOW_SIZE_N_ITEMS) ); rach_cnfg.add_field( new parser::field_enum_num ("mac_con_res_timer", &data->rr_config_common_sib.rach_cnfg.mac_con_res_timer, liblte_rrc_mac_contention_resolution_timer_num, LIBLTE_RRC_MAC_CONTENTION_RESOLUTION_TIMER_N_ITEMS) ); rach_cnfg.add_field( new parser::field("max_harq_msg3_tx", &data->rr_config_common_sib.rach_cnfg.max_harq_msg3_tx) ); parser::section groupa_cnfg("preambles_group_a_cnfg"); rach_cnfg.add_subsection(&groupa_cnfg); groupa_cnfg.set_optional(&data->rr_config_common_sib.rach_cnfg.preambles_group_a_cnfg.present); groupa_cnfg.add_field( new parser::field_enum_num ("size_of_ra", &data->rr_config_common_sib.rach_cnfg.preambles_group_a_cnfg.size_of_ra, liblte_rrc_size_of_ra_preambles_group_a_num, LIBLTE_RRC_SIZE_OF_RA_PREAMBLES_GROUP_A_N_ITEMS) ); groupa_cnfg.add_field( new parser::field_enum_num ("msg_size", &data->rr_config_common_sib.rach_cnfg.preambles_group_a_cnfg.msg_size, liblte_rrc_message_size_group_a_num, LIBLTE_RRC_MESSAGE_SIZE_GROUP_A_N_ITEMS) ); groupa_cnfg.add_field( new parser::field_enum_num ("msg_pwr_offset_group_b", &data->rr_config_common_sib.rach_cnfg.preambles_group_a_cnfg.msg_pwr_offset_group_b, liblte_rrc_message_power_offset_group_b_num, LIBLTE_RRC_MESSAGE_POWER_OFFSET_GROUP_B_N_ITEMS) ); // BCCH configuration parser::section bcch_cnfg("bcch_cnfg"); rr_config.add_subsection(&bcch_cnfg); bcch_cnfg.add_field( new parser::field_enum_num ("modification_period_coeff", &data->rr_config_common_sib.bcch_cnfg.modification_period_coeff, liblte_rrc_modification_period_coeff_num, LIBLTE_RRC_MODIFICATION_PERIOD_COEFF_N_ITEMS) ); // PCCH configuration parser::section pcch_cnfg("pcch_cnfg"); rr_config.add_subsection(&pcch_cnfg); pcch_cnfg.add_field( new parser::field_enum_num ("default_paging_cycle", &data->rr_config_common_sib.pcch_cnfg.default_paging_cycle, liblte_rrc_default_paging_cycle_num, LIBLTE_RRC_DEFAULT_PAGING_CYCLE_N_ITEMS) ); pcch_cnfg.add_field( new parser::field_enum_str ("nB", &data->rr_config_common_sib.pcch_cnfg.nB, liblte_rrc_nb_text, LIBLTE_RRC_NB_N_ITEMS) ); // PRACH configuration parser::section prach_cnfg("prach_cnfg"); rr_config.add_subsection(&prach_cnfg); prach_cnfg.add_field( new parser::field("root_sequence_index", &data->rr_config_common_sib.prach_cnfg.root_sequence_index) ); 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", &data->rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag) ); prach_cnfg_info.add_field( new parser::field("prach_config_index", &data->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index) ); prach_cnfg_info.add_field( new parser::field("prach_freq_offset", &data->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset) ); prach_cnfg_info.add_field( new parser::field("zero_correlation_zone_config", &data->rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config) ); // PDSCH configuration parser::section pdsch_cnfg("pdsch_cnfg"); rr_config.add_subsection(&pdsch_cnfg); pdsch_cnfg.add_field( new parser::field("p_b", &data->rr_config_common_sib.pdsch_cnfg.p_b) ); pdsch_cnfg.add_field( new parser::field("rs_power", &data->rr_config_common_sib.pdsch_cnfg.rs_power) ); // PUSCH configuration parser::section pusch_cnfg("pusch_cnfg"); rr_config.add_subsection(&pusch_cnfg); pusch_cnfg.add_field( new parser::field("n_sb", &data->rr_config_common_sib.pusch_cnfg.n_sb) ); pusch_cnfg.add_field( new parser::field_enum_str ("hopping_mode", &data->rr_config_common_sib.pusch_cnfg.hopping_mode, liblte_rrc_hopping_mode_text, LIBLTE_RRC_HOOPPING_MODE_N_ITEMS) ); pusch_cnfg.add_field( new parser::field ("pusch_hopping_offset", &data->rr_config_common_sib.pusch_cnfg.pusch_hopping_offset) ); pusch_cnfg.add_field( new parser::field ("enable_64_qam", &data->rr_config_common_sib.pusch_cnfg.enable_64_qam) ); // PUSCH-ULRS configuration parser::section ulrs_cnfg("ul_rs"); pusch_cnfg.add_subsection(&ulrs_cnfg); ulrs_cnfg.add_field( new parser::field ("cyclic_shift", &data->rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift) ); ulrs_cnfg.add_field( new parser::field ("group_assignment_pusch", &data->rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch) ); ulrs_cnfg.add_field( new parser::field ("group_hopping_enabled", &data->rr_config_common_sib.pusch_cnfg.ul_rs.group_hopping_enabled) ); ulrs_cnfg.add_field( new parser::field ("sequence_hopping_enabled", &data->rr_config_common_sib.pusch_cnfg.ul_rs.sequence_hopping_enabled) ); // PUCCH configuration parser::section pucch_cnfg("pucch_cnfg"); rr_config.add_subsection(&pucch_cnfg); pucch_cnfg.add_field( new parser::field_enum_num ("delta_pucch_shift", &data->rr_config_common_sib.pucch_cnfg.delta_pucch_shift, liblte_rrc_delta_pucch_shift_num,LIBLTE_RRC_DELTA_PUCCH_SHIFT_N_ITEMS) ); pucch_cnfg.add_field( new parser::field ("n_rb_cqi", &data->rr_config_common_sib.pucch_cnfg.n_rb_cqi) ); pucch_cnfg.add_field( new parser::field ("n_cs_an", &data->rr_config_common_sib.pucch_cnfg.n_cs_an) ); pucch_cnfg.add_field( new parser::field ("n1_pucch_an", &data->rr_config_common_sib.pucch_cnfg.n1_pucch_an) ); // 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", &data->rr_config_common_sib.ul_pwr_ctrl.p0_nominal_pusch) ); ul_pwr_ctrl.add_field( new parser::field_enum_num ("alpha", &data->rr_config_common_sib.ul_pwr_ctrl.alpha, liblte_rrc_ul_power_control_alpha_num, LIBLTE_RRC_UL_POWER_CONTROL_ALPHA_N_ITEMS) ); ul_pwr_ctrl.add_field( new parser::field ("p0_nominal_pucch", &data->rr_config_common_sib.ul_pwr_ctrl.p0_nominal_pucch) ); ul_pwr_ctrl.add_field( new parser::field ("delta_preamble_msg3", &data->rr_config_common_sib.ul_pwr_ctrl.delta_preamble_msg3) ); // Delta Flist PUCCH parser::section delta_flist("delta_flist_pucch"); ul_pwr_ctrl.add_subsection(&delta_flist); delta_flist.add_field( new parser::field_enum_num ("format_1", &data->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_1, liblte_rrc_delta_f_pucch_format_1_num, LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1_N_ITEMS) ); delta_flist.add_field( new parser::field_enum_num ("format_1b", &data->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_1b, liblte_rrc_delta_f_pucch_format_1b_num, LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_1B_N_ITEMS) ); delta_flist.add_field( new parser::field_enum_num ("format_2", &data->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_2, liblte_rrc_delta_f_pucch_format_2_num, LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2_N_ITEMS) ); delta_flist.add_field( new parser::field_enum_num ("format_2a", &data->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_2a, liblte_rrc_delta_f_pucch_format_2a_num, LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2A_N_ITEMS) ); delta_flist.add_field( new parser::field_enum_num ("format_2b", &data->rr_config_common_sib.ul_pwr_ctrl.delta_flist_pucch.format_2b, liblte_rrc_delta_f_pucch_format_2b_num, LIBLTE_RRC_DELTA_F_PUCCH_FORMAT_2B_N_ITEMS) ); // Run parser with single section return parser::parse_section(filename, &sib2); } int enb::parse_sib3(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *data) { parser::section sib3("sib3"); // CellReselectionInfoCommon parser::section resel_common("cell_reselection_common"); sib3.add_subsection(&resel_common); resel_common.add_field( new parser::field_enum_num ("q_hyst", &data->q_hyst, liblte_rrc_q_hyst_num, LIBLTE_RRC_Q_HYST_N_ITEMS) ); parser::section speed_resel("speed_state_resel_params"); resel_common.add_subsection(&speed_resel); resel_common.set_optional(&data->speed_state_resel_params.present); parser::section q_hyst_sf("q_hyst_sf"); speed_resel.add_subsection(&q_hyst_sf); q_hyst_sf.add_field( new parser::field_enum_num ("medium", &data->speed_state_resel_params.q_hyst_sf.medium, liblte_rrc_sf_medium_num, LIBLTE_RRC_SF_MEDIUM_N_ITEMS) ); q_hyst_sf.add_field( new parser::field_enum_num ("high", &data->speed_state_resel_params.q_hyst_sf.high, liblte_rrc_sf_high_num, LIBLTE_RRC_SF_HIGH_N_ITEMS) ); parser::section mob_params("mobility_state_params"); speed_resel.add_subsection(&mob_params); mob_params.add_field( new parser::field_enum_num ("t_eval", &data->speed_state_resel_params.mobility_state_params.t_eval, liblte_rrc_t_evaluation_num, LIBLTE_RRC_T_EVALUATION_N_ITEMS) ); mob_params.add_field( new parser::field_enum_num ("t_hyst_normal", &data->speed_state_resel_params.mobility_state_params.t_hyst_normal, liblte_rrc_t_hyst_normal_num, LIBLTE_RRC_T_HYST_NORMAL_N_ITEMS) ); mob_params.add_field( new parser::field ("n_cell_change_medium", &data->speed_state_resel_params.mobility_state_params.n_cell_change_medium) ); mob_params.add_field( new parser::field ("n_cell_change_high", &data->speed_state_resel_params.mobility_state_params.n_cell_change_high) ); // CellReselectionServingFreqInfo parser::section resel_serving("cell_reselection_serving"); sib3.add_subsection(&resel_serving); resel_serving.add_field( new parser::field ("s_non_intra_search", &data->s_non_intra_search, &data->s_non_intra_search_present) ); resel_serving.add_field( new parser::field("thresh_serving_low", &data->thresh_serving_low) ); resel_serving.add_field( new parser::field("cell_resel_prio", &data->cell_resel_prio) ); // intraFreqCellReselectionInfo parser::section intra_freq("intra_freq_reselection"); sib3.add_subsection(&intra_freq); intra_freq.add_field( new parser::field("q_rx_lev_min", &data->q_rx_lev_min) ); intra_freq.add_field( new parser::field("p_max", &data->p_max, &data->p_max_present) ); intra_freq.add_field( new parser::field("s_intra_search", &data->s_intra_search, &data->s_intra_search_present) ); intra_freq.add_field( new parser::field_enum_num ("allowed_meas_bw", &data->allowed_meas_bw, liblte_rrc_allowed_meas_bandwidth_num, LIBLTE_RRC_ALLOWED_MEAS_BANDWIDTH_N_ITEMS, &data->allowed_meas_bw_present) ); intra_freq.add_field( new parser::field("presence_ant_port_1", &data->presence_ant_port_1) ); intra_freq.add_field( new parser::field("neigh_cell_cnfg", &data->neigh_cell_cnfg) ); intra_freq.add_field( new parser::field("t_resel_eutra", &data->t_resel_eutra) ); parser::section t_resel_eutra_sf("t_resel_eutra_sf"); intra_freq.add_subsection(&t_resel_eutra_sf); t_resel_eutra_sf.set_optional(&data->t_resel_eutra_sf_present); t_resel_eutra_sf.add_field( new parser::field_enum_num ("sf_medium", &data->t_resel_eutra_sf.sf_medium, liblte_rrc_sssf_medium_num, LIBLTE_RRC_SSSF_MEDIUM_N_ITEMS) ); t_resel_eutra_sf.add_field( new parser::field_enum_num ("sf_high", &data->t_resel_eutra_sf.sf_high, liblte_rrc_sssf_high_num, LIBLTE_RRC_SSSF_HIGH_N_ITEMS) ); // Run parser with single section return parser::parse_section(filename, &sib3); } int enb::parse_sib4(std::string filename, LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *data) { parser::section sib4("sib4"); // csg-PhysCellIdRange parser::section csg_range("csg_phys_cell_id_range"); sib4.add_subsection(&csg_range); csg_range.set_optional(&data->csg_phys_cell_id_range_present); csg_range.add_field( new parser::field_enum_num ("range", &data->csg_phys_cell_id_range.range, liblte_rrc_phys_cell_id_range_num, LIBLTE_RRC_PHYS_CELL_ID_RANGE_N_ITEMS) ); csg_range.add_field( new parser::field("start", &data->csg_phys_cell_id_range.start) ); // 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)); // 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)); // Run parser with single section return parser::parse_section(filename, &sib4); } uint32_t HexToBytes(const std::string& str, uint8_t *char_value, uint32_t buff_len) { uint32_t i=0; for (i = 0; i < str.length() && i("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(filename, &sib9)) { data->hnb_name_present = true; if (name_enabled) { strncpy((char*) data->hnb_name, hnb_name.c_str(), 47); data->hnb_name[47] = 0; data->hnb_name_size = strnlen(hnb_name.c_str(), 48); } else if (hex_enabled) { data->hnb_name_size = HexToBytes(hex_value, data->hnb_name, 48); } else { data->hnb_name_present = false; } return 0; } else { return -1; } } int enb::parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_common) { LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *sib1 = &rrc_cfg->sibs[0].sib.sib1; rrc_cfg->sibs[0].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1; LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2 = &rrc_cfg->sibs[1].sib.sib2; rrc_cfg->sibs[1].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2; LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3 = &rrc_cfg->sibs[2].sib.sib3; rrc_cfg->sibs[2].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3; LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT *sib4 = &rrc_cfg->sibs[3].sib.sib4; rrc_cfg->sibs[3].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4; LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT *sib9 = &rrc_cfg->sibs[8].sib.sib9; rrc_cfg->sibs[8].sib_type = LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9; // Read SIB1 configuration from file bzero(sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); if (parse_sib1(args->enb_files.sib_config, sib1)) { return -1; } // Fill rest of data from enb config sib1->cell_id = (args->enb.s1ap.enb_id << 8) + args->enb.s1ap.cell_id; sib1->tracking_area_code = args->enb.s1ap.tac; sib1->freq_band_indicator = srslte_band_get_band(args->rf.dl_earfcn); sib1->N_plmn_ids = 1; sib1->plmn_id[0].id.mcc = args->enb.s1ap.mcc; sib1->plmn_id[0].id.mnc = args->enb.s1ap.mnc; sib1->plmn_id[0].resv_for_oper = LIBLTE_RRC_NOT_RESV_FOR_OPER; sib1->cell_barred = LIBLTE_RRC_CELL_NOT_BARRED; sib1->q_rx_lev_min_offset = 0; // Generate SIB2 bzero(sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); if (parse_sib2(args->enb_files.sib_config, sib2)) { return -1; } // SRS not yet supported sib2->rr_config_common_sib.srs_ul_cnfg.present = false; if (sib2->ul_bw.present) { switch(args->enb.n_prb) { case 6: sib2->ul_bw.bw = LIBLTE_RRC_UL_BW_N6; break; case 15: sib2->ul_bw.bw = LIBLTE_RRC_UL_BW_N15; break; case 25: sib2->ul_bw.bw = LIBLTE_RRC_UL_BW_N25; break; case 50: sib2->ul_bw.bw = LIBLTE_RRC_UL_BW_N50; break; case 75: sib2->ul_bw.bw = LIBLTE_RRC_UL_BW_N75; break; case 100: sib2->ul_bw.bw = LIBLTE_RRC_UL_BW_N100; break; } } if (sib2->arfcn_value_eutra.present) { sib2->arfcn_value_eutra.value = args->rf.ul_earfcn; } // Generate SIB3 if defined in mapping info if (sib_is_present(sib1->sched_info, sib1->N_sched_info, LIBLTE_RRC_SIB_TYPE_3)) { bzero(sib3, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT)); if (parse_sib3(args->enb_files.sib_config, sib3)) { return -1; } } // Generate SIB4 if defined in mapping info if (sib_is_present(sib1->sched_info, sib1->N_sched_info, LIBLTE_RRC_SIB_TYPE_4)) { bzero(sib4, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_4_STRUCT)); if (parse_sib4(args->enb_files.sib_config, sib4)) { return -1; } } // Generate SIB9 if defined in mapping info if (sib_is_present(sib1->sched_info, sib1->N_sched_info, LIBLTE_RRC_SIB_TYPE_9)) { bzero(sib9, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_9_STRUCT)); if (parse_sib9(args->enb_files.sib_config, sib9)) { return -1; } } // Copy PHY common configuration bzero(phy_config_common, sizeof(phy_cfg_t)); memcpy(&phy_config_common->prach_cnfg, &sib2->rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT)); memcpy(&phy_config_common->pdsch_cnfg, &sib2->rr_config_common_sib.pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT)); memcpy(&phy_config_common->pusch_cnfg, &sib2->rr_config_common_sib.pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT)); memcpy(&phy_config_common->pucch_cnfg, &sib2->rr_config_common_sib.pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT)); memcpy(&phy_config_common->srs_ul_cnfg, &sib2->rr_config_common_sib.srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT)); return 0; } bool enb::sib_is_present(LIBLTE_RRC_SCHEDULING_INFO_STRUCT *sched_info, uint32_t nof_sched_info, LIBLTE_RRC_SIB_TYPE_ENUM sib_num) { for (uint32_t i=0;ienb.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; } bzero(&rrc_cfg->antenna_info, sizeof(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT)); rrc_cfg->antenna_info.tx_mode = (LIBLTE_RRC_TRANSMISSION_MODE_ENUM) (args->enb.transmission_mode - 1); if (rrc_cfg->antenna_info.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3) { rrc_cfg->antenna_info.ue_tx_antenna_selection_setup = LIBLTE_RRC_UE_TX_ANTENNA_SELECTION_OPEN_LOOP; rrc_cfg->antenna_info.ue_tx_antenna_selection_setup_present = false; rrc_cfg->antenna_info.codebook_subset_restriction_choice = LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM3; rrc_cfg->antenna_info.codebook_subset_restriction = 0b11; rrc_cfg->antenna_info.codebook_subset_restriction_present = true; } else if (rrc_cfg->antenna_info.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { rrc_cfg->antenna_info.ue_tx_antenna_selection_setup = LIBLTE_RRC_UE_TX_ANTENNA_SELECTION_CLOSED_LOOP; rrc_cfg->antenna_info.ue_tx_antenna_selection_setup_present = true; rrc_cfg->antenna_info.codebook_subset_restriction_choice = LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM4; rrc_cfg->antenna_info.codebook_subset_restriction = 0b111111; rrc_cfg->antenna_info.codebook_subset_restriction_present = true; } /* Parse power allocation */ rrc_cfg->pdsch_cfg = LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS; for (int i = 0; i < LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS; i++) { if (args->enb.p_a == liblte_rrc_pdsch_config_p_a_num[i]) { rrc_cfg->pdsch_cfg = (LIBLTE_RRC_PDSCH_CONFIG_P_A_ENUM) i; } } if (rrc_cfg->pdsch_cfg == LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS) { 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); mac_cnfg.set_optional(&rrc_cfg->mac_cnfg.phr_cnfg.setup_present); phr_cnfg.add_field( new parser::field_enum_str ("dl_pathloss_change", &rrc_cfg->mac_cnfg.phr_cnfg.dl_pathloss_change, liblte_rrc_dl_pathloss_change_text, LIBLTE_RRC_DL_PATHLOSS_CHANGE_N_ITEMS) ); phr_cnfg.add_field( new parser::field_enum_num ("periodic_phr_timer", &rrc_cfg->mac_cnfg.phr_cnfg.periodic_phr_timer, liblte_rrc_periodic_phr_timer_num, LIBLTE_RRC_PERIODIC_PHR_TIMER_N_ITEMS) ); phr_cnfg.add_field( new parser::field_enum_num ("prohibit_phr_timer", &rrc_cfg->mac_cnfg.phr_cnfg.prohibit_phr_timer, liblte_rrc_prohibit_phr_timer_num, LIBLTE_RRC_PROHIBIT_PHR_TIMER_N_ITEMS) ); parser::section ulsch_cnfg("ulsch_cnfg"); mac_cnfg.add_subsection(&ulsch_cnfg); rrc_cfg->mac_cnfg.ulsch_cnfg.tti_bundling = false; ulsch_cnfg.add_field( new parser::field_enum_num ("max_harq_tx", &rrc_cfg->mac_cnfg.ulsch_cnfg.max_harq_tx, liblte_rrc_max_harq_tx_num, LIBLTE_RRC_MAX_HARQ_TX_N_ITEMS, &rrc_cfg->mac_cnfg.ulsch_cnfg.max_harq_tx_present) ); ulsch_cnfg.add_field( new parser::field_enum_num ("periodic_bsr_timer", &rrc_cfg->mac_cnfg.ulsch_cnfg.periodic_bsr_timer, liblte_rrc_periodic_bsr_timer_num, LIBLTE_RRC_PERIODIC_BSR_TIMER_N_ITEMS, &rrc_cfg->mac_cnfg.ulsch_cnfg.periodic_bsr_timer_present) ); ulsch_cnfg.add_field( new parser::field_enum_num ("retx_bsr_timer", &rrc_cfg->mac_cnfg.ulsch_cnfg.retx_bsr_timer, liblte_rrc_retransmission_bsr_timer_num, LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_N_ITEMS) ); mac_cnfg.add_field( new parser::field_enum_num ("time_alignment_timer", &rrc_cfg->mac_cnfg.time_alignment_timer, liblte_rrc_time_alignment_timer_num, LIBLTE_RRC_TIME_ALIGNMENT_TIMER_N_ITEMS) ); /* 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( new parser::field_enum_num ("dsr_trans_max", &rrc_cfg->sr_cfg.dsr_max, liblte_rrc_dsr_trans_max_num, LIBLTE_RRC_DSR_TRANS_MAX_N_ITEMS) ); 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 ("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)); // Run parser with two sections parser p(args->enb_files.rr_config); p.add_section(&mac_cnfg); p.add_section(&phy_cfg); return p.parse(); } 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; } 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); } int field_qci::parse(libconfig::Setting &root) { uint32_t nof_qci = root.getLength(); bzero(cfg, sizeof(rrc_cfg_qci_t)*MAX_NOF_QCI); for (uint32_t i=0;i discard_timer ("discard_timer", &cfg[qci].pdcp_cfg.discard_timer, liblte_rrc_discard_timer_num, LIBLTE_RRC_DISCARD_TIMER_N_ITEMS); if (discard_timer.parse(q["pdcp_config"])) { cfg[qci].pdcp_cfg.discard_timer_present = false; } else { cfg[qci].pdcp_cfg.discard_timer_present = true; } parser::field_enum_num pdcp_sn_size ("pdcp_sn_size", &cfg[qci].pdcp_cfg.rlc_um_pdcp_sn_size, liblte_rrc_pdcp_sn_size_num, LIBLTE_RRC_PDCP_SN_SIZE_N_ITEMS); if (pdcp_sn_size.parse(q["pdcp_config"])) { cfg[qci].pdcp_cfg.rlc_um_pdcp_sn_size_present = false; } else { cfg[qci].pdcp_cfg.rlc_um_pdcp_sn_size_present = true; } if (q["pdcp_config"].lookupValue("status_report_required", cfg[qci].pdcp_cfg.rlc_am_status_report_required)) { cfg[qci].pdcp_cfg.rlc_am_status_report_required_present = true; } else { cfg[qci].pdcp_cfg.rlc_am_status_report_required_present = false; } // Parse RLC section if (q["rlc_config"].exists("ul_am")) { cfg[qci].rlc_cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM; } else if (q["rlc_config"].exists("ul_um") && q["rlc_config"].exists("dl_um")) { cfg[qci].rlc_cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_BI; } else if (q["rlc_config"].exists("ul_um") && !q["rlc_config"].exists("dl_um")) { cfg[qci].rlc_cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_UNI_UL; } else if (!q["rlc_config"].exists("ul_um") && q["rlc_config"].exists("dl_um")) { cfg[qci].rlc_cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_UNI_DL; } else { fprintf(stderr, "Invalid combination of UL/DL UM/AM for qci=%d\n", qci); return -1; } // Parse RLC-UM section if (q["rlc_config"].exists("ul_um")) { LIBLTE_RRC_UL_UM_RLC_STRUCT *rlc_cfg = &cfg[qci].rlc_cfg.ul_um_bi_rlc; if (cfg[qci].rlc_cfg.rlc_mode == LIBLTE_RRC_RLC_MODE_UM_UNI_UL) { rlc_cfg = &cfg[qci].rlc_cfg.ul_um_bi_rlc; } parser::field_enum_num sn_field_len ("sn_field_length", &rlc_cfg->sn_field_len, liblte_rrc_sn_field_length_num, LIBLTE_RRC_SN_FIELD_LENGTH_N_ITEMS); sn_field_len.parse(q["rlc_config"]["ul_um"]); } if (q["rlc_config"].exists("dl_um")) { LIBLTE_RRC_DL_UM_RLC_STRUCT *rlc_cfg = &cfg[qci].rlc_cfg.dl_um_bi_rlc; if (cfg[qci].rlc_cfg.rlc_mode == LIBLTE_RRC_RLC_MODE_UM_UNI_DL) { rlc_cfg = &cfg[qci].rlc_cfg.dl_um_bi_rlc; } parser::field_enum_num sn_field_len ("sn_field_length", &rlc_cfg->sn_field_len, liblte_rrc_sn_field_length_num, LIBLTE_RRC_SN_FIELD_LENGTH_N_ITEMS); sn_field_len.parse(q["rlc_config"]["dl_um"]); parser::field_enum_num t_reordering ("t_reordering", &rlc_cfg->t_reordering, liblte_rrc_t_reordering_num, LIBLTE_RRC_T_REORDERING_N_ITEMS); t_reordering.parse(q["rlc_config"]["dl_um"]); } // Parse RLC-AM section if (q["rlc_config"].exists("ul_am")) { LIBLTE_RRC_UL_AM_RLC_STRUCT *rlc_cfg = &cfg[qci].rlc_cfg.ul_am_rlc; parser::field_enum_num t_poll_retx ("t_poll_retx", &rlc_cfg->t_poll_retx, liblte_rrc_t_poll_retransmit_num, LIBLTE_RRC_T_POLL_RETRANSMIT_N_ITEMS); t_poll_retx.parse(q["rlc_config"]["ul_am"]); parser::field_enum_num poll_pdu ("poll_pdu", &rlc_cfg->poll_pdu, liblte_rrc_poll_pdu_num, LIBLTE_RRC_POLL_PDU_N_ITEMS); poll_pdu.parse(q["rlc_config"]["ul_am"]); parser::field_enum_num poll_byte ("poll_byte", &rlc_cfg->poll_byte, liblte_rrc_poll_byte_num, LIBLTE_RRC_POLL_BYTE_N_ITEMS); poll_byte.parse(q["rlc_config"]["ul_am"]); parser::field_enum_num max_retx_thresh ("max_retx_thresh", &rlc_cfg->max_retx_thresh, liblte_rrc_max_retx_threshold_num, LIBLTE_RRC_MAX_RETX_THRESHOLD_N_ITEMS); max_retx_thresh.parse(q["rlc_config"]["ul_am"]); } if (q["rlc_config"].exists("dl_am")) { LIBLTE_RRC_DL_AM_RLC_STRUCT *rlc_cfg = &cfg[qci].rlc_cfg.dl_am_rlc; parser::field_enum_num t_reordering ("t_reordering", &rlc_cfg->t_reordering, liblte_rrc_t_reordering_num, LIBLTE_RRC_T_REORDERING_N_ITEMS); t_reordering.parse(q["rlc_config"]["dl_am"]); parser::field_enum_num t_status_prohibit ("t_status_prohibit", &rlc_cfg->t_status_prohibit, liblte_rrc_t_status_prohibit_num, LIBLTE_RRC_T_STATUS_PROHIBIT_N_ITEMS); t_status_prohibit.parse(q["rlc_config"]["dl_am"]); } // 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; } LIBLTE_RRC_UL_SPECIFIC_PARAMETERS_STRUCT *lc_cfg = &cfg[qci].lc_cfg; parser::field priority ("priority", &lc_cfg->priority); priority.parse(q["logical_channel_config"]); parser::field_enum_num prioritized_bit_rate ("prioritized_bit_rate", &lc_cfg->prioritized_bit_rate, liblte_rrc_prioritized_bit_rate_num, LIBLTE_RRC_PRIORITIZED_BIT_RATE_N_ITEMS); prioritized_bit_rate.parse(q["logical_channel_config"]); parser::field_enum_num bucket_size_duration ("bucket_size_duration", &lc_cfg->bucket_size_duration, liblte_rrc_bucket_size_duration_num, LIBLTE_RRC_BUCKET_SIZE_DURATION_N_ITEMS); bucket_size_duration.parse(q["logical_channel_config"]); parser::field log_chan_group ("log_chan_group", &lc_cfg->log_chan_group); if (log_chan_group.parse(q["logical_channel_config"])) { lc_cfg->log_chan_group_present = false; } else { lc_cfg->log_chan_group_present = true; } cfg[qci].configured = true; } return 0; } }